java堆内存溢出能获取cpu使用率吗,需要倒入jar吗

       首先搞清楚java堆内存溢出栈空间存儲的是什么java堆内存溢出栈空间是线程私有的,是java堆内存溢出方法执行的内存模型每个方法执行时都会在java堆内存溢出栈空间产生一个栈幀,存放方法的变量表返回值等信息,方法的执行到结束就是一个栈帧入栈到出栈的过程

    所以栈溢出的原因一般是循环调用方法导致棧帧不断增多,栈深度不断增加最终没有内存可以分配,出现StackOverflowError比如下面这种情况:

 
栈内存溢出一般是程序错误导致,如递归死循环等等
 
java堆内存溢出堆是线程共有的区域,主要用来存放对象实例几乎所有的java堆内存溢出对象都在这里分配内存,也是JVM内存管理最大的区域java堆内存溢出堆内存分年轻代和年老代,堆内存溢出一般是年老代溢出当程序不断地创建大量对象实例并且没有被GC回收时,就容易产生內存溢出当一个对象产生时,主要过程是这样的:
JVM首先在年轻代的Eden区为它分配内存;
若分配成功则结束,否则JVM会触发一次Young GC试图释放Eden區的不活跃对象;
如果释放后还没有足够的内存空间,则将Eden区部分活跃对象转移到Suvivor区Suvivor区长期存活的对象会被转移到老年代;
当老年代空間不够,会触发Full GC对年老代进行完全的垃圾回收;
回收后如果Suvivor和老年代仍没有充足的空间接收从Eden复制过来的对象,使得Eden区无法为新产生的對象分配内存即溢出。
由此可见当程序不断地创建大量对象实例并且没有被GC回收时,就容易产生内存溢出如下:
 
堆内存溢出很可能伴随内存泄漏,应首先排查可能泄露的对象再通过工具检查GC roots引用链,从而发现泄露对象是由于何种引用关系使得GC无法回收他们;若不存茬内存泄漏换句话说就是内存中的对象还都需要继续存活,则可通过修改虚拟机的堆参数将堆内存增大
 
永久代也是java堆内存溢出堆内存嘚一部分,主要用来存放Class的相关信息如类名,访问修饰符等等一般永久代溢出的原因是动态加载大量的Class并且没有及时被GC回收。只能通過调整永久代内存参数的方式解决
 
我们知道,操作系统对每个进程的内存都是有一定限制的当堆内存和非堆内存分配过大时,剩余的內存不足以创建足够的线程栈就会产生OutOfMemoryError。因此我们可以增大进程占用的总内存或减小堆内存等来解决问题
  • 栈内存溢出:程序所要求的棧深度过大导致。
  • 堆内存溢出: 分清 内存泄露还是 内存容量不足泄露则看对象如何被 GC Root 引用。不足则通过 调大 -Xms-Xmx参数。
  • 持久带内存溢出:Class對象未被释放Class对象占用信息过多,有过多的Class对象
  • 无法创建本地线程:总容量不变,堆内存非堆内存设置过大,会导致能给线程的内存不足
 


在C++ 语言中如果需要动态分配一塊内存,程序员需要负责这块内存的整个生命周期从申请分配、到使用、再到最后的释放。这样的过程非常灵活但是却十分繁琐,程序员很容易由于疏忽而忘记释放内存从而导致内存的泄露。 java堆内存溢出 语言对内存管理做了自己的优化这就是垃圾回收机制。 java堆内存溢出 的几乎所有内存对象都是在堆内存上分配(基本数据类型除外)然后由 GC ( garbage collection)负责自动回收不再使用的内存。

上面是java堆内存溢出 内存管理机制的基本情况但是如果仅仅理解到这里,我们在实际的项目开发中仍然会遇到内存泄漏的问题也许有人表示怀疑,既然 java堆内存溢出 的垃圾回收机制能够自动的回收内存怎么还会出现内存泄漏的情况呢?这个问题我们需要知道 GC 在什么时候回收内存对象,什么样嘚内存对象会被 GC 认为是“不再使用”的

java堆内存溢出中对内存对象的访问,使用的是引用的方式在 java堆内存溢出 代码中我们维护一个内存對象的引用变量,通过这个引用变量的值我们可以访问到对应的内存地址中的内存对象空间。在 java堆内存溢出 程序中这个引用变量本身既可以存放堆内存中,又可以放在代码栈的内存中(与基本数据类型相同) GC 线程会从代码栈中的引用变量开始跟踪,从而判定哪些内存昰正在使用的如果 GC 线程通过这种方式,无法跟踪到某一块堆内存那么 GC 就认为这块内存将不再使用了(因为代码中已经无法访问这块内存了)。

通过这种有向图的内存管理方式当一个内存对象失去了所有的引用之后,GC 就可以将其回收反过来说,如果这个对象还存在引鼡那么它将不会被 GC 回收,哪怕是 java堆内存溢出 虚拟机抛出 OutOfMemoryError

一般来说内存泄漏有两种情况。一种情况如在C/C++ 语言中的在堆中的分配的内存,在没有将其释放掉的时候就将所有能访问这块内存的方式都删掉(如指针重新赋值);另一种情况则是在内存对象明明已经不需要的時候,还仍然保留着这块内存和它的访问方式(引用)第一种情况,在 java堆内存溢出 中已经由于垃圾回收机制的引入得到了很好的解决。所以 java堆内存溢出 中的内存泄漏,主要指的是第二种情况

在这个例子中,代码栈中存在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堆内存溢出 的内存溢出会导致程序效率低下、占用大量不需要的内存等问题。这将导致整个机器性能变差严重的也会引起拋出 OutOfMemoryError ,导致程序崩溃

一般情况下内存泄漏的避免

在不涉及复杂数据结构的一般情况下,java堆内存溢出 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度我们有时也将其称为“对象游离”。

在这段代码中FileSearch 类中有一个函数 hasString ,用来判断文档中是否含有指萣的字符串流程是先将mFile 加载到内存中,然后进行判断但是,这里的问题是将 content 声明为了实例变量,而不是本地变量于是,在此函数返回之后内存中仍然存在整个文件的数据。而很明显这些数据我们后续是不再需要的,这就造成了内存的无故浪费

要避免这种情况丅的内存泄露,要求我们以C/C++ 的内存管理思维来管理自己分配的内存第一,是在声明对象引用之前明确内存对象的有效作用域。在一个函数内有效的内存对象应该声明为 local 变量,与类实例生命周期相同的要声明为实例变量……以此类推第二,在内存对象不再需要时记嘚手动将其引用置空。

java堆内存溢出中的几种引用方式

java堆内存溢出中有几种不同的引用方式它们分别是:强引用、软引用、弱引用和虚引鼡。下面我们首先详细地了解下这几种引用方式的意义。

在此之前我们介绍的内容中所使用的引用 都是强引用这是使用最普遍的引用。如果一个对象具有强引用那就类似于必不可少的生活用品,垃圾回收器绝不会回收它当内存空 间不足,java堆内存溢出 虚拟机宁愿抛出 OutOfMemoryError 錯误使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题

SoftReference 类的一个典型用途就是用于内存敏感的高速缓存。 SoftReference  的原理是:在保持对对象的引用时保证在  JVM  报告内存不足情况之前将清除所有的软引用关键之处在于,垃圾收集器在运行时可能会(也可能鈈会)释放软可及对象对象是否被释放取决于垃圾收集器的算法 以及垃圾收集器运行时可用的内存数量。

WeakReference 类的一个典型用途就是规范化映射( canonicalized mapping )另外,对于那些生存期相对较长而且重新创建的开销也不高的对象来说弱引用也比较有用。关键之处在于垃圾收集器运行時如果碰到了弱可及对象,将释放  WeakReference  引用的对象然而,请注意垃圾收集器可能要运行多次才能找到并释放弱可及对象。

PhantomReference  对象引用的对象巳经结束可供收集了。这使您能够刚好在对象占用的内存被回收之前采取行动 Reference与 ReferenceQueue 的配合使用。

我要回帖

更多关于 java堆内存溢出 的文章

 

随机推荐