一、 HotSpot堆内存结构
现在JVM基本上都是HotSpot。接下来先看看堆内存的结构
HotSpot将堆内存分成上面三部分,分别是:新生代(Young Generation)、老年代(Old Generation)、持久代(Permanent Generation)。先大体说下这三部分的作用,然后循序渐进进行深入,学习知识也是要迭代多次,才能更好的理解,一口吃不了一个大胖子,这是题外话了。
新生代(Young Generation)
新创建的类绝大部分都被分配到这个区域。由于大部分对象创建后很快会不可达到,所以绝大部分对象在新生代创建,然后很快销毁。对象从新生代销毁的过程叫Minor GC。(翻译一下:小型的垃圾回收
与老年代、持久代不同的是,新生代又被分为三个部分,即上图的Eden,S0,S1。先记住新生代的这三个子部分,下文具体说明。
老年代(Old Generation)
从新生代对象没有不可达,并且存活下来,会被拷贝到这个区域。这个区域所占的空间比新生代的大,也正是因为这个空间比较大,所以GC的频率比新生代少很多。对象从老年代销毁的过程叫Major GC。(翻译一下:大型的垃圾回收)
持久代(Permanent Generation)
本人很喜欢这个区域,因为他够持久!男人就要持久。。。
这个区域也被叫做方法区,存放字节码等文件,常量池也是位于这区域。这个区域如果达到阈值会触发Full GC。Full GC 会清理新生代,老年代以及持久代三个区域。
总结:为什么堆区域会分新生代和老年代?对于大部分应用,常驻对象不多。因为大部分存活寿命不长,新生代和老年代的划分有利于区分对待和缩小垃圾回收范围。(Most allocated objects are not referenced (considered live) for long, that is, they die young. Few references from older to younger objects exist.)
二、HotSpot内存回收策略
GC(垃圾回收)的一般思路是标记live objects →是否压缩→清理→压缩。
新生代GC(YouGC)
Minor GC作用于新生代,从上文可知新生代分为Eden ,S0,S1三个区域,Eden用于生成新的对象,另外两部分是救助区(Survivor Space),这两部分总是转换From、To的角色。先扫描Eden,把存活的对象复制到To,如果To放不下的对象直接拷贝到老年代;再从From区扫描存活的对象,如果达到存活次数的阈值就移动到老年代,剩下的拷贝到To区。这一套完成后From和To的角色互换,维持活动对象在救助区的不断复制,直到它们进入OldGen。(From和To对应上面的S0和S1)
老年代GC(OldGC)
Major GC作用于老年代,相比新生代的YouGC频率很高,Major GC的执行的频率很少。识别过程大致是:识别存活的对象,识别垃圾并回收,然后滑动对象并压缩对象到持续的空间。
总结如下
三、四种内存泄露
- 栈溢出(StackOverflowError)
- 堆溢出(OutOfMemoryError:java heap space)
- 持久代溢出(OutOfMemoryError: PermGen space)
- OutOfMemoryError:unable to create native thread
栈溢出StackOverflowError:出现这种错误一般是由于程序问题引起的,比如死递归等。我们知道在函数中基本变量和对象的引用都是在栈内存中分配。当在函数中定义了一个变量时,栈内存会给这个变量分配内存。当超过变量的作用域后,GC将会释放为该变量分配的内存空间。但是如果死递归一直不会结束,并且每一次递归生成的局部变量都不会释放,因为函数还在执行。最终栈不可访问,抛出StackOverflowError.
堆溢出OutOfMemoryError:java heap space: 堆内存溢出会抛出OOME,出现这种问题有可能是内存泄露,也可能是内存溢出。这两种情况比较麻烦,我还在研究阶段。先挖个坑,研究明白了补上。
持久代溢出(OutOfMemoryError: PermGen space):HotSpot jvm通过持久代实现了java虚拟机规范的方法区,这个区域存放的是class对象、程序运行时的常量池。所以OutOfMemoryError:PermGen space有可能是常量池溢出,也有可能是class对象没有及时释放而引起的溢出。常见的有以下几种情况:
1.我们平时修改好代码并保存,tomcat会进行热部署。这时候很可能抛出OutOfMemoryError: PermGen space。这是因为原来的class对象没有卸载掉,新的class对象加入方法区,达到方法区的阈值后抛出异常。
2如果应用程序本身比较大,涉及的类库比较多,但是我们分配给持久带的内存(通过-XX:PermSize和-XX:MaxPermSize来设置)比较小的时候也可能出现此种问题。
3.class动态生成技术,比如CGLib动态代理等,这种情况下需要更大的方法区空间来存储动态生成的class对象。
OutOfMemoryError:unable to create native thread:字面意思是内存溢出:无法创建新的线程。字面意思已经很明显了,出现这种情况的原因基本下面2点
1.程序创建的线程数超过操作系统的限制。
2.JVM占用的内存太多,导致创建线程的内存空间太小。我们都知道操作系统对每个进程的内存是有限制的,我们启动Jvm,相当于启动了一个进程,假如我们一个进程占用了4G的内存,那么通过下面的公式计算出来的剩余内存就是建立线程栈的时候可以用的内存。 线程栈总可用内存=4G-(-Xmx的值)- (-XX:MaxPermSize的值)- 程序计数器占用的内存
通过上面的公式我们可以看出,-Xmx 和 MaxPermSize的值越大,那么留给线程栈可用的空间就越小,在-Xss参数配置的栈容量不变的情况下,可以创建的线程数也就越小。因此如果是因为这种情况导致的unable to create native thread
,那么要么我们增大进程所占用的总内存,或者减少-Xmx或者-Xss来达到创建更多线程的目的。
相关推荐
程序运行要用到的内存大于虚拟机能提供的最大内存就发生内存溢出了, 内存溢出的问题要看业务和系统大小而定,对于某些系统可能内存溢出不常见,但某些系统还是很常见的解决的方法
jvm内存溢出 学习笔记
简单的判断JVM内存溢出的方法
JVM内存dump分析工具MAT独立安装包,分析内存溢出利器,可以准确定位内存异常原因,解决问题,MemoryAnalyzer-1.10.0.20200225.zip
JVM内存溢出的解决方案以及相关描述和TOMACAT参数配置
tomcat修改JVM内存配置(解决大项目内存溢出问题有效方案)
对tomcat jvm内存进行修改,以避免tomcat内存溢出。
深入理解JVM内存区域与内存溢出异常
JVM实战-对象访问与内存溢出异常解析
关于JVM内存溢出的原因分析及解决方案探讨.docx
有的时候,我们需要一次查询很多的数据,或者是说每次查询的数据量都很大,都有可能早晨内存溢出的情况,所以我们今天分别针对三个数据库来探讨如何避免这一问题。
jvm堆内存溢出jar包代码
2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解...环境搭建以及jdk,jre,jvm的关系 免费 00:20:48 第4讲 jvm初体验-内存溢出问题的分
Linux环境的Tomcat JVM内存优化 java虚拟机内存溢出问题的解决
该文档整合了网上所有的关于描述was(webSphere)下生成许多phd文件的...产生该类文件的原因包括JVM设置的最小内存太小,以至于内存溢出,还有就是程序漏洞,使得JVM内存溢出,文档中叶介绍了websphere的检测工具的使用
JVM原理及内存溢出案列分析PPT教案学习.pptx
jvm内存溢出解决方法,详细内容看下面解释
MyEclipse开发工具中如何配置jvm虚拟机内存,防止开发过程中内存溢出
主要是针对JVM内存溢出,服务器宕机,内存优化,溢出类型进行介绍
Tomcat内存溢出的三种情况及解决办法分析 Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出。造成内存原因是不一样的,当然处理方式也不一样。 这里根据平时遇到的情况和相关资料进行一个...