coolrainman 2019-06-25
转载请注明出处 http://www.paraller.com
原文排版地址 点击获取更好阅读体验
但垃圾收集效果难以令人满意:针对常量池的回收以及类的卸载(十分苛刻)
当Old区再被塞满,就会触发FullGC,回收最后能回收的空间
局部变量表的内存空间在编译期就已经分配完成
发挥的作用与jvm stack相同,但是为虚拟机使用到的Native方法服务,hotspot虚拟机将两个合而为一
java程序通过栈上的reference数据操作 堆上的 具体对象
虚拟机栈中reference数据称为引用
reference类型的数据中储存的数值代表的是另外一块内存的起始地址,就称这块内存是代表着引用
除了 被引用和不被引用两种状态 ;JDK1.2之后引入了四种新的概念:强引用、软引用、弱引用、虚引用
主流的方式有两种,直接指针和使用句柄
访问句柄: reference中保存着对象的具体地址。优点是快速。
主要存放类信息,通过CGLib动态构造类会造成OOM异常,比如jsp的构造
每当有一个地方引用+1 ,计数器为0说明没有对象引用它 , 存在两个无用对象相互引用的情况
主流方式;以GC Roots对象为起点,根据是否有引用链可达判断;哪些可以称为引用链:
PS
:对象如何在被标记回收的时候逃脱: 覆写finalize方法,将this赋值给某个类变量或者对象的成员变量
指某些对象不再被应用程序使用,而垃圾收集器(Garbage Collector)却没能识别它们是“不再使用的”。如果那些不使用的对象占用堆(heap)空间足够大,使得应用程序无法满足下一次内存分配需求,就会导致OutOfMemoryError错误
内存不够用了,原因有几种,内存泄露只是其中一种。
一般是 OutOfMemoryError :先确定是内存溢出还是内存泄露(垃圾回收处理机制)
内存泄露:通过工具查看泄露对象到GC Roots的引用链,找到无法回收的原因
内存溢出:调到物理内存,判断是否对象生命周期过长
线程请求的栈深度大于虚拟机栈所允许的最大深度;单线程的时候,无论是栈帧太大还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是这个异常
它保存了Java类定义,并且这些类定义是不会变成“无用”的,是吗?事实上,它们是可以变成“无用”的。以一个部署到应用程序服务器的Java web程序来说,当该应用程序被卸载的时候,你的EAR/WAR包中的所有类都将变得无用。只要应用程序服务器还活着,JVM将继续运行,但是一大堆的类定义将不再使用,理应将它们从永久代(PermGen)中移除。如果不移除的话,我们在永久代(PermGen)区域就会有内存泄漏。
类加载器(classloader)泄漏的一个可能的场景就是通过运行的线程(而内存泄漏)。当你的程序,或者你的程序使用的第三方库(我经常遇到这种情况,比如Quartz)开启了一些长时间运行的线程。一个例子:一个用于周期性执行代码的计时器(timer)线程。
如果不解决该线程预期的生命周期问题,我们直接会遇到麻烦。当你程序的任何一部分启动一个线程的时候,你要确保它不会比程序活得还要久。在典型的情况下,开发者要么不知道自己有责任处理好这个问题,或者忘了写清理(clean-up)的代码。
否则,如果应用程序卸载后,线程还在继续运行,它通常将维持一个到web应用程序的classloader的引用,即我们所说的contextclassloader。这也就意味着,所有卸载掉的应用程序仍然保存在内存中。怎么解决?如果是你的程序开启了新线程,那么你就应该在卸载的时候关闭它们,这可以通过使用一个servlet context listener来实现。如果是第三方库开启的新线程,你应该搜索它的关闭线程的接口,如果没有的话,就上报一个bug吧。
另一个典型的内存泄漏原因是由数据库驱动造成的。我们在和Plumbr一起发布的demo程序中遇到了这种内存泄漏情况。它是一个与Sprint MVC一起发布的、代码稍微修改过的Pet Clinic程序。让我们关注一下当这个应用程序部署到服务器上的时候,发生了什么:
现在,当从服务器上卸载应用程序的时候,java.sql.DriverManager仍将持有那个引用,无论在HSQLDB库,或者在Spring framework中,都没有代码可以移除它!正如上面解释的那样,一个jdbcDriver对象将持有一个到org.hsqldb.jdbcDriver类的引用,从而持有用于加载应用程序的java.lang.Classloader的一个实例的引用。这个classloader现在仍然引用着应用程序的所有类。在我们那特殊的demo应用程序中,在程序启动的时候,需要加载将近2000个类,占用约10MB永久代(PermGen)内存。这就意味着需要5~10次重新部署,才会将默认大小的永久代(PermGen)塞满,然后就会触发java.lang.OutOfMemoryError: PermGen space错误并崩溃。
怎样解决此问题?一个可能的办法就是写一个servlet content listener,用于在应用程序关闭的时候,从DriverManager反注册HSQLDB驱动。这个方法很直接,但是请记住——你需要在使用该驱动的每一个应用程序中都这么写。
你的应用程序遇到java.lang.OutOfMemoryError: PermGen space错误的原因很多,究其根本原因,大多数是由于object或程序的class loader加载的类的引用已经无用了导致的。对此类问题,你需要采取的补救措施都非常相似,即,首先,找出引用在哪里被持有;其次,给你的web应用程序添加一个关闭的hook,或者在应用程序卸载后移除引用。你要么通过servlet context listener,要么通过第三方库提供的API来实现这一点。
非jvm运行时数据区;新加入了的NIO类,引入了"Channel"与"Buffer"的I/O方式
通过本地函数库分配一个堆外内存,然后通过java堆的的对象实例buffer作为这块内存的引用进行操作,因为避免了再java heap and native heap之间
进行复制操作,显著的提高性能,当对于jvm的各个内存总和大于直接内存会报错
句柄:简而言之数据的地址需要变动,变动以后就需要有人来记录管理变动,(就好像户籍管理一样),因此系统用句柄来记载数据地址的变更
Presenting the Permanent Generation
[[原创](翻译)什么是Java的永久代(PermGen)内存泄漏](http://ju.outofmemory.cn/entr...