JVM内存区域划分详解2017年

 

为防止忘记,摘抄自:https://blog.csdn.net/JackCaptain1015/article/details/71195010

 

-Xms设置堆的最小空间大小。
-Xmx设置堆的最大空间大小。
-Xmn:设置年轻代大小。
-XX:NewSize设置新生代最小空间大小。
-XX:MaxNewSize设置新生代最大空间大小。
-XX:PermSize设置永久代最小空间大小。
-XX:MaxPermSize设置永久代最大空间大小。
-Xss设置每个线程的堆栈大小
-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
典型JVM参数配置参考:
java-Xmx3550m-Xms3550m-Xmn2g-Xss128k
-XX:ParallelGCThreads=20
-XX:+UseConcMarkSweepGC-XX:+UseParNewGC
-Xmx3550m:设置JVM最大可用内存为3550M。
-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2g:设置年轻代大小为2G。整个堆大小=年轻代大小+年老代大小+持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,官方推荐配置为整个堆的3/8。
-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

 

本文吸取《深入理解java虚拟机》与多篇博客精华详细解说了JVM中内存划分的情况。

大多数 JVM 将内存区域划分:

(1)Method Area(Non-Heap)(方法区) ——线程共享

(2)Heap(堆) ——线程共享

(3)Program Counter Register(程序计数器) ——非线程共享

(4)VM Stack(虚拟机栈,也有翻译成JAVA 方法栈的)——非线程共享

(5)Native Method Stack ( 本地方法栈 )——非线程共享

JVM运行的时候会分配好 Method Area(方法区) 和Heap(堆),而JVM 每遇到一个线程,就为其分配一个 Program Counter Register(程序计数器) , VM Stack(虚拟机栈)和Native Method Stack (本地方法栈), 当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。

非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与JAVA程序运行生命周期相同,所以,gc只发生在线程共享的区域(大部分发生在Heap上)的原因。

线程共享:

一、方法区

(1)有时候也称为永久代(Permanent Generation),在该区内很少发生垃圾回收,在这里进行的GC主要是方法区里的常量池和类型的卸载。

(2)方法区主要用来存储已被虚拟机加载的类信息、常量、静态变量和即时编译后的代码等数据。

(3)方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。运行时生成的常量也会存在这个常量池中。比如String类的 intern()方法。

(4)扩展:

-XX:MaxPermSize设置上限
-XX:PermSize设置最小值 例:VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M

二、堆

(1)在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。

(2)堆空间分为老年代和年轻代。刚创建的对象存放在年轻代,而老年代中存放生命周期长久的实例对象。年轻代中又被分为Eden区(圣经中的伊甸园)、和两个Survivor区(From Space和To Space)。新的对象分配是首先放在Eden区,Survivor区作为Eden区和Old区的缓冲,在Survivor区的对象经历若干次收集仍然存活的,就会被转移到老年代。

(3)堆中垃圾回收的时候注意一个大对象回收过程,描述如下:
假设年轻代与老年代空间分配如下:Eden:80M、S1:10M、S2:10M、老年代:100M

过程:

1)新建60M的对象O1,此时Eden有足够内存吃下,所以60M被分配到Eden区。
2)再新建40M对象O2,此时因为S1和S2的控件不足以容纳下O1,所以O1被直接分配到老年代,而O2进入Eden区
3)清空O1、O2,新建90M对象O3,发现Eden不足以放下O3,O3被直接放入老年代中
4)清空O3,新建110M对象O4,O4发现Eden和老年代都没有足够控件,直接返回OutOfMemoryError

结论:

1)当一个对象大于eden区而小于old区(老年代)时的时候会直接扔到old区。
2)而但对象大于old区时,会直接抛出OutOfMemoryError(OOM)。

扩展:

参数-XX:PretenureSizeThreshold:这个参数的单位是Byte,
其作用是当新对象申请的内存空间大于这个参数值的时候,直接扔到old区。
-Xms:设置最小值
-Xmx:设置最大值 例:VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
若-Xms=-Xmx,则可避免堆自动扩展。
-XX:+HeapDumpOnOutOfMemoryError:
JVM会在遇到OutOfMemoryError时拍摄一个“堆转储快照”,并将其保存在一个文件中。

线程私有:

一、虚拟机栈:

(1)虚拟机栈也就是我们平常所称的栈内存,它为java方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。

(2)局部变量表里存储的是基本数据类型和对象引用。局部变量所需的内存空间在编译器间确定。

(3)每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。动态链接就是将常量池中的符号引用在运行期转化为直接引用。

-Xoss参数设置本地方法栈大小(对于HotSpot无效)
-Xss参数设置栈容量 例: -Xss128k

二、本地方法栈

本地方法栈和虚拟机栈类似,只不过本地方法栈为Native方法服务。

三、程序计数器

代表着当前线程所执行字节码的行号指示器。
分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。
程序计数器是唯一一个java虚拟机规范没有规定任何OOM(Out Of Memory)情况的区域。
 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值