关于内存释放的问题 easy~

Stieven 发布于 2014/06/12 22:10
阅读 428
收藏 0

@中山野鬼 你好,想跟你请教个问题:为什么不可以连续释放内存 就像这样:

int *p = new int;

delete p;

delete p;

是不是内存是有标记的?然后再次释放会去检查这个标记,没有标记就报错了


加载中
0
中山野鬼
中山野鬼
C++的权当我不会。太违背理性的一种语言。哈哈。
幻の上帝
幻の上帝
和C根本上就是一个原因。
0
中山野鬼
中山野鬼

引用来自“中山野鬼”的评论

C++的权当我不会。太违背理性的一种语言。哈哈。
补充解释一下,无尽的人类对象化思维和计算机过程化执行中的纠结。又想要女人,又想要男人,最终恐怕连人妖都满足不了,虽然人妖也是人。哈。这方面,倒还不如java来的纯粹。。
幻の上帝
幻の上帝
就Java的奇葩设计还有脸说啥纯粹?阉了还差不多。连个确定性析构都没有;存储都管不干净非得自欺欺人把具有类似union{T obj; T* ptr;}类型的玩意儿叫成什么“对象”还跟primitive type势不两立;用类型擦除当泛型糊弄用户玩……根本就是罄竹难书嘛。
雨翔河
雨翔河
这话有意思,不过容易引起战争,哈哈
S
Stieven
。。。。。。
0
ericsoul
ericsoul
delete是释放内存还给操作系统,你已经释放了,操作系统就会回收,可能这个时候已经把它又分配给别人了,你就不能再操作它了。当然一般这部分空间还在你这个程序内部,如果你中间new了一个别的变量就分配给它了。所以一般delete完,就要把指针置空,避免出现野指针。至于你说的标记,这部分是操作系统实现的,可能是。
S
Stieven
谢谢啊
0
catch2000
catch2000

C++不太清楚。

对于C语言而言,在Linux中,当使用malloc分配内存的时候,返回的指针,它指向的内存地址之前的四个字节,记录了内存的大小(自己的电脑测试下来,记录的大小比分配的大小大9,应该是记录其他内容用的),同时Linux内存管理系统会标记内存已使用。当我们使用free的使用,系统会根据记录的内存大小来释放内存。这个时候,Linux的内存管理系统会标记内存已释放。

当我们再次释放的时候,free会执行同样的操作,即根据传入的参数指向的内存地址之前的四个字节的大小来释放内存,这个时候Linux内存管理系统应该会出问题。

因为free可以释放空指针,即NULL。所以,多次释放NULL,是可以的。这也是为什么建议释放后,置位NULL。可以避免double free导致的错误。

对于C++,机制应该有些相似。仅供参考。

幻の上帝
幻の上帝
C++的delete和free类似允许空指针值。
S
Stieven
受教了 谢谢啊
0
S
Stieven
今晚做了一下测试,代码是这样的: 
int * psome = new int[10];
    delete psome;
    psome[2] = 10;
    int * p = new int;
    *p = 900;
    delete p;
    for(int i =0 ; i<100 ;i++){
        sleep(1); //休眠1s
        cout<<*p<<endl;
        cout<<psome - p<<endl;
    }
    return 0;
然后其结果是虽然p被释放了,但是我们还是可以访问*p的内容,*p的结果还是900,而且psome与p的内存地址相隔就是12吧,好像是动态内存分配就是在一个区域内的。我是这样想的:每个独立的程序的动态内存是有固定的区域的,不知对不对啊
幻の上帝
幻の上帝
回复 @catch2000 : 不管是C还是C++的实现都不需要指望操作系统的支持。没有操作系统照样有malloc/new。
catch2000
catch2000
回复 @幻の上帝 : 因为不同的操作系统内存管理算法是不一样的,我们不能依靠它们。这里我提到的操作系统,不只是Linux与Windows的区别,还有Rtems, Vxworks, uc/OS,eCos,以及Contiki。我们不能期望它们能有什么相似的内存管理算法。毕竟C语言只是语言,内存管理是我们通过算法来实现的,不是语言的范畴了。
幻の上帝
幻の上帝
回复 @catch2000 : 脱离具体实现无所谓什么堆区。对C++来说就叫free storage。对于C来说连个正式的称呼都没有,只知道这里的对象具有allocated storage duration。
幻の上帝
幻の上帝
靠具体实现的结果来解释是彻头彻尾的方法论错误。
catch2000
catch2000
对于你这里的psome-p操作,是有风险的。在你的系统上是这样,但是在其他系统上不一定。没有指向同一数组(或者分配的内存)的指针,一般是要避免他们的大小比较和加减运算。因为这样的结果是未定义的。 可以参见:《MISRA C 2004》(这份文档是一个C安全子集)
下一页
0
catch2000
catch2000

引用来自“Stieven”的评论

今晚做了一下测试,代码是这样的: 
int * psome = new int[10];
    delete psome;
    psome[2] = 10;
    int * p = new int;
    *p = 900;
    delete p;
    for(int i =0 ; i<100 ;i++){
        sleep(1); //休眠1s
        cout<<*p<<endl;
        cout<<psome - p<<endl;
    }
    return 0;
然后其结果是虽然p被释放了,但是我们还是可以访问*p的内容,*p的结果还是900,而且psome与p的内存地址相隔就是12吧,好像是动态内存分配就是在一个区域内的。我是这样想的:每个独立的程序的动态内存是有固定的区域的,不知对不对啊
动态内存分配,是由操作系统的内存管理算法决定的。一般都是系统的内存管理算法预先申请一段内存备用,标记为可用。如果用户向系统申请内存,则内存管理系统检查是否有可用内存,如果有则将可用的内存分配给用户。同时将,分配给用户的内存,标记为不可用。如果预先申请的内存被用完,则内存管理系统会再次向操作系统申请内存。
我们释放内存,是内存管理系统将此段内存,由原来的不可用,标记为可用。对于是否刷新此段内存,由具体的内存管理算法决定。
对于指针而言,既然它指向的内存地址存在,而且是在可用的范围内(分配的内存在堆中),所以释放分配的内存后,指向他的地址的指针可以使用。但是,具体的值,就是不确定的了。
如果这段内存,没有被内存管理系统刷新,而且没有再被分配及使用。则此段内存的值,不会变化。所以,指向它的指针,获取的内容也没有变化。
0
catch2000
catch2000

引用来自“中山野鬼”的评论

引用来自“中山野鬼”的评论

C++的权当我不会。太违背理性的一种语言。哈哈。
补充解释一下,无尽的人类对象化思维和计算机过程化执行中的纠结。又想要女人,又想要男人,最终恐怕连人妖都满足不了,虽然人妖也是人。哈。这方面,倒还不如java来的纯粹。。
C++的内存处理方式沿用了C的——由用户处理。而C设计的初衷,就是尊重使用者的意愿,认为使用者知道自己在做什么。而JAVA是自己管理,难免会有不符合使用者的想法(释放某段内存,重新使用)。当然,JAVA的目的就是使开发更容易,屏蔽掉开发者对于底层的考虑。从这一点考虑,JAVA对内存的管理也实现了它的目的。
所以,不论是C,C++,JAVA它们都用各自的目标。它们也都很好的实现了自己的目标。对于超过目标之外的,还是选择其他的语言更为合适,不能对于语言过于苛求。
0
幻の上帝
幻の上帝

跟C类似,ISO C++规定在这种用法就是undefined behavior,不保证任何可预测的行为,后果自负。

说白了还是责任分配问题。实现有权假定用户正确地遵守了约定不作死。

具体细节具体实现管。没给出环境之前进一步纠结没意义。(因为ISO C++支持独立实现,你还没法让人假定操作系统的存在。)





返回顶部
顶部