java内存管理机制在C++语言中,如果需要动态分配一块内存,程序员需要负责这块内存的整个生命周期。从申请分配,到使用,再到发放许可证。这个过程很灵活,但也很繁琐,程序员很容易因为疏忽而忘记释放内存,造成内存泄漏。java语言对内存管理做了自己的优化,也就是垃圾回收机制。java中几乎所有的内存对象都分配在堆内存上(基本数据类型除外),然后gc(garbagecollection)负责自动回收不再使用的内存。以上就是java内存管理机制的基本情况。但是如果我们只了解这一点,在实际的项目开发中还是会遇到内存泄漏的情况。可能有人会表示疑惑,既然java的垃圾回收机制可以自动回收内存,怎么会出现内存泄漏呢?对于这个问题,我们需要知道gc什么时候回收内存对象,什么样的内存对象被gc认为“不再使用”。java中访问内存对象使用引用。在java代码中,我们维护一个内存对象的引用变量。通过这个引用变量的值,我们可以访问对应内存地址中的内存对象空间。在java程序中,引用变量本身可以存放在堆内存中,也可以存放在代码栈的内存中(与基本数据类型相同)。gc线程会从代码栈中的引用变量开始跟踪,以确定正在使用的内存。如果gc线程无法通过这种方式追踪到某块堆内存,那么gc就认为这块内存将不再被使用(因为代码无法再访问这块内存)。通过这种有向图内存管理方式,当一个内存对象失去所有引用时,gc可以回收它。反之,如果这个对象还有引用,即使java虚拟机抛出outofmemoryerror,也不会被gc回收。Java内存泄漏一般来说,有两种类型的内存泄漏。一种情况,如c/c++语言,当堆中分配的内存没有释放时,所有能访问这块内存的方法都被删除(如指针重赋值);一种情况是,当内存对象明显不再需要时,内存及其访问方法(引用)仍然保留。由于引入了垃圾回收机制,第一种情况在java中得到了很好的解决。所以java中的内存泄漏主要是指第二种情况。可能概念太抽象了,可以看看这个例子:vectorv=newvector(10);for(inti=1;i<100;i++){objecto=newobject;v.添加(o);?=空;在这个例子中,vector对象的引用v和object对象的引用o都存在于代码栈中。在for循环中,我们不断的产生新的对象,然后将它们添加到vector对象中,然后使o引用无效。问题是当o引用被清空时,如果发生gc,我们创建的object对象是否可以被gc回收?答案是否定的。因为,gc在追踪代码栈中的引用时,会找到v引用,继续往下追踪,会发现v引用指向的内存空间中存在object对象的引用。也就是说虽然o引用已经被清空,但是object对象还有其他引用,可以访问,所以gc无法释放。如果经过这个循环,object对象对程序没有任何影响,那么我们就认为这个java程序发生了内存泄漏。虽然对于c/c++中的内存泄漏,java内存泄漏的破坏性较小。除了少数情况下程序崩溃外,大多数情况下程序仍然可以正常运行。但是在移动设备对内存和cpu有严格限制的情况下,java的内存溢出会造成程序效率低下,占用大量无用内存等问题。这会导致整机性能下降,严重时会抛出outofmemory错误,导致程序崩溃。一般内存泄漏的避免在一般不涉及复杂数据结构的情况下,java中的内存泄漏表现为内存对象的生命周期超过了程序需要它的时间长度。我们有时也将此称为“对象游荡”。例如:publicclassfilesearch{privatebytecontent;私有文件mfile;公共文件搜索(文件文件){mfile=file;}publicbooleanhasstring(stringstr){intsize=getfilesize(mfile);内容=新字节[大小];加载文件(mfile,内容);字符串s=新字符串(内容);返回s.contains(str);}}这段代码中,filesearch类中有一个函数hasstring,用于判断文档中是否包含指定的字符串。过程是先把mfile加载到内存中,然后再做判断。但是,这里的问题是content被声明为实例变量,而不是局部变量。因此,该函数返回后,整个文件的数据仍然存在于内存中。而且很明显,我们后面不需要这些数据,这就造成了无缘无故的内存浪费。为了避免这种情况下的内存泄漏,就需要我们用c/c++的内存管理思想来管理自己分配的内存。***是在声明对象引用之前明确内存对象的有效范围。在函数内有效的内存对象应该声明为局部变量,与类实例具有相同生命周期的内存对象应该声明为实例变量……等等。其次,当不再需要内存对象时,记得手动取消它的引用。复杂数据结构中的内存泄漏在实际项目中,我们经常会使用一些比较复杂的数据结构来缓存程序运行过程中需要的数据信息。有时,由于数据结构过于复杂,或者我们有一些特殊的要求(例如,只要内存允许,尽可能多地缓存信息以提高程序的运行速度等),很难实现我们来控制数据结构中的数据。生命周期是明确定义的。这时候我们可以使用java中的一种特殊机制来防止内存泄漏。之前我们介绍过,java的gc机制是基于跟踪内存的引用机制。在此之前,我们使用的引用只定义了一种形式的“objecto;”。其实这只是java引用机制中的一种默认情况。此外,还有其他参考方法。通过使用这些特殊的引用机制,配合gc机制,我们可以实现一些我们需要的效果。
