JVM内存布局及演变
-Xms1024m:设置初始化内存分配大小,默认为本地内存的1/64。
-Xmx1024m:设置最大分配内存,默认为本地内存的1/4。
底层方法,与native方法相关。
线程私有,内存连续,存放8大基本类型+对象引用+实例的方法引用。
也叫PC寄存器,线程私有,保存当前执行指令的地址。
线程共享,内存不连续,存放对象实例。
-XX:+HeapDumpOnOutOfMemoryError:OOM
方法区是一个JVM规范上的逻辑概念,实际的位置根据不同JVM来看。
hotspotJVM虚拟机上将堆中的永久代作为方法区的一个存储实现,为的是方法区也可以用堆内存的GC垃圾回收机制,而不用重新针对方法区做GC操作,直接使用堆内存的GC就可以了。
存放静态变量(static)、常量(final)、类信息(Class,如构造方法、接口定义)、常量池。实例变量存在堆内存中,和方法区无关。
在Java7中永久代中存储的部分数据已经开始转移到JavaHeap或NativeMemory中了。比如,符号引用(Symbols)转移到了NativeMemory;字符串常量池(internedstrings)、类的静态变量(classstatics)转移到了JavaHeap,永久代中存放类和类加载器的元数据信息。
移除堆中的永久区,用占用本地内存的元空间(MetaSpace)来代替,存放类和类加载器的元数据信息。
符号引用没有存在元空间中,而是继续存在nativeheap中,这是两个方式和位置,不过都可以算作是本地内存,在虚拟机之外进行划分,没有设置限制参数时只受物理内存大小限制,即只有占满了操作系统可用内存后才OOM。
-XX:MetaspaceSize来调整元空间初始大小,最大为本地内存大小。
感谢您的阅读,本文已同步到我的个人博客,您的关注是对我最大的鼓励!
Java程序运行时,操作系统内存与JVM内存的各自作用???
当然。
把JVM看成是个中间层就可以,不止是内存分配,还有线程、网络连接等等,最终在底层都要靠操作系统来搞。
Java语言的设计思想,本来就是对C语言这种可以直接进行操作系统调用的语言的一种简化。引入了一个隔离层,让jvm来当个中介,以简化应用开发。让程序员集中精力于实现业务逻辑。
JVM内存管理
JVM全称JavaVirtualMachine,也就是我们耳熟能详的Java虚拟机。它能识别.class后缀的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作。
元空间大小参数:
堆大小参数:
-Xms:堆的最小值;
-Xmx:堆的最大值;
-Xmn:新生代的大小;
-XX:NewSize;新生代最小值;
-XX:MaxNewSize:新生代最大值;
例如-Xmx256m
功能
(1)运行时常量池溢出
(2)方法区中保存的Class对象没有被及时回收掉或者Class信息占用的内存超过了我们配置。
注意Class要被回收,条件比较苛刻(仅仅是可以,不代表必然,因为还有一些参数可以进行控制):
1、该类所有的实例都已经被回收,也就是堆中不存在该类的任何实例。
2、加载该类的ClassLoader已经被回收。
3、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
JVM内存结构
()类装载子系统
装载连接初始化
()方法区被所有线程共享垃圾收集也会清理方法区中的无用类型对象
a类型信息类加载器加载类时从类文件中提取出来
类的完整有效名
父类的完整有效名(interfaceandjavalangObject除外因为无父类)
类型的修饰符
类型直接接口列表
b常量池存储了一个类型所使用的常量所有类型域和方法的符号引用
c域信息jvm必须在方法区中保存类型的所有域的相关信息以及域的声明顺序
域的相关信息包括
域名
域类型
域修饰符(publicprivateprotectedstaticfinalvolatiletransient…)
d方法信息
方法名
方法返回类型
方法参数
方法的修饰符
方法的字节码(abstractandnative除外)(被PC寄存器指向)
操作数栈和方法栈帧的局部变量区的大小
异常表
e类的静态变量(所有对象共享一分拷贝)
f类的被声明为final的类变量(所有对象共享一分拷贝)
g加载一个类的类加载器的引用
hClass类的引用
i方法表
j一个例子
ClassLava{
privateintspeed=;
voidflow();
}
ClassVolcano{
publicstaticvoidmain(String[]args){
Lavalava=newLava();
lavaflow();
}
}
下面我们描述一下main()方法的第一条指令的字节码是如何被执行的不同的jvm实现的差别很大这里只是其中之一
为了运行这个程序你以某种方式把Volcano传给了jvm有了这个名字jvm找到了这个类文件(Volcanoclass)并读入它从类文件提取了类型信息并放在了方法区中通过解析存在方法区中的字节码jvm激活了main()方法在执行时jvm保持了一个指向当前类(Volcano)常量池的指针
注意jvm在还没有加载Lava类的时候就已经开始执行了正像大多数的jvm一样不会等所有类都加载了以后才开始执行它只会在需要的时候才加载
main()的第一条指令告知jvm为列在常量池第一项的类分配足够的内存
jvm使用指向Volcano常量池的指针找到第一项发现是一个对Lava类的符号引用然后它就检查方法区看lava是否已经被加载了
这个符号引用仅仅是类lava的完整有效名lava这里我们看到为了jvm能尽快从一个名称找到一个类一个良好的数据结构是多么重要这里jvm的实现者可以采用各种方法如hash表查找树等等同样的算法可以用于Class类的forName()的实现
当jvm发现还没有加载过一个称为Lava的类它就开始查找并加载类文件Lavaclass它从类文件中抽取类型信息并放在了方法区中
jvm于是以一个直接指向方法区lava类的指针替换了常量池第一项的符号引用以后就可以用这个指针快速的找到lava类了而这个替换过程称为常量池解析(constantpoolresolution)在这里我们替换的是一个native指针
jvm终于开始为新的lava对象分配空间了这次jvm仍然需要方法区中的信息它使用指向lava数据的指针(刚才指向volcano常量池第一项的指针)找到一个lava对象究竟需要多少空间
一旦jvm知道了一个Lava对象所要的空间它就在堆上分配这个空间并把这个实例的变量speed初始化为缺省值假如lava的父对象也有实例变量则也会初始化
当把新生成的lava对象的引用压到栈中第一条指令也结束了下面的指令利用这个引用激活java代码把speed变量设为初始值另外一条指令会用这个引用激活Lava对象的flow()方法
()堆存放运行时所有对象和数组
()栈每次启动一个新的线程就会被分配一个栈
()PC寄存器(程序计数器)
总是指向该线程下一步要执行的指令指令的位置放在方法区的方法字节码中内容是相对于第一个指令的偏移量
lishixinzhi/Article/program/Java/hx/201311/26491
JVM基础和内存区域剖析
概念
特点
先进后出
虚拟机栈:用户描述Java方法执行的内存模型
栈帧:虚拟机栈中的栈元素(用于支持虚拟机进行方法调用和方法执行的数据结构)包括局部变量表、操作数栈、动态链接、方法出口
1.主要存储:
2.数据过多会导致OutOfMemoryError异常
JDK1.8
=JDK1.8
和永久代的区别:
1.存储位置不同,永久代物理上是堆的一部分,和新手代,老年代地址是连续的,而元空间属于本地内存;
2.存储内容不同,元空间存储类的元信息,静态变量和常量池等并入堆中;
3.相当于永久代的数据被分到了堆和元空间中
直接内存:避免native空间和java堆中来回进行复制
虚拟机启动时创建,用于存放对象实例,几乎所有的对象(包含常量池)都在堆上分配内存,当对象无法再该空间申请到内存时将抛出OutOfMemoryError异常。同时也是垃圾收集器管理的主要区域。可通过-Xmx–Xms参数来分别指定最大堆和最小堆
GC主要管理区域,可以通过-Xmx和Xms来设置最大和最小值,也可以通过-XX:NewSize-XX:MaxNewSize设置年轻代初始大小
超出空间大小会抛出OutOfMemoryError异常
新生区
新生区分为两个部分:伊甸区(Edenspace)和幸存者区(survivorspace)
伊甸区(Edenspace)
大部分对象都会在Eden区诞生,并且一段时间不使用就会被GC回收
幸存者区(survivorspace)
存在一段时间还在使用的对象会进入survivor区,survivor区包含一个相对的From区和to区,两者来回copy,回收没用的对象,用来延长对象的生命周期。
老年区(oldFullGC)
经过多次GC仍然存在的对象会移动到老年区中,若老年区也满了,则会产生MajorGC(FullGC),对老年区进行内存清理(STW),若老年区执行了FullGC之后发现还是无法进行对象的报错,那么就会产生OOM异常”OutOfMemoryError“
问题:空间不连续,浪费空间
复制算法有2块一样大小的空间,情况对象时将可用的对象移动到to区里,复制算法内存空间连续
问题:要用2块空间,所以内存的模型from和to非常的小
只用一块空间,先进行标记无用对象,然后整理内存空间地址,最后清除
它只有一条GC线程,且就像前面说的,它在运行的时候需要暂停用户程序(stoptheworld)STW
它有多条GC线程,且它也需要暂停用户程序(stoptheworld)STW
它有一条或多条GC线程,且它需要在部分阶段暂停用户程序(stoptheworld),部分阶段与用户程序并发执行
serial(用于新生代,采用复制算法)、serialold(用于年老代,采用标记/整理算法)
parNew(用于新生代,采用复制算法)、Parallel
Scavenge(用于新生代,采用复制算法)、Parallel
old(用于年老代,采用标记/整理算法)
concurrentmarksweep[CMS](用于年老代,采用标记/清除算法)
JVM内存分配参数
JVM会试图将系统内存尽可能地限制在-Xms中,当内存实际使用量触及-Xms指定的大小时,会触发FullGC。因此把-Xms值设置为-Xmx时,可以在系统运行初期减少GC操作的次数和耗时。