JVM基础篇——内存结构

一、java内存模型




java类加载时类的类型信息、方法列表会保存到方法区中,然后在堆内存中创建一个Class对象。

堆(-Xmx和-Xms):所有线程共享,存放new的对象和数组,GC管理的主区域。

Java7内存划分:


  Java8内存划分:                        



  • Eden GC时,存活对象会被移动到S0(幸存区),并清空Eden,每次GC,对象GC年龄增加,当年龄超过15(默认可配置XX:MaxTenuringThreshold),对象被移动到老年代。

  • 元空间直接占用本地内存,默认动态调节,可通过MaxMetaspaceSize配置

常见堆内存溢出:OutOfMemoryError:  Java heap space。一般指创建的对象过多,导致无法再申请到足够的内存空间,可通过dump工具分析内存日志。

jmap –histo pid >d:/a.log查看堆内存对象数量大小

jmap –heap pid >d:/b.log查看堆内存使用情况

jmap -dump:format=b,file=d:/m.datpid 查看内存详情情况

生成的dat文件可通过jhat查看

jhat -port 5000 d:/m.dat 

然后通过浏览器访问http://localhost:5000/

Jstatck命令参考下一篇

:存放局部变量、操作栈、动态链接、方法出口、对象的引用等,是线程私有。

局部变量表:存放基本类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,不是对象本身,只是对象的起始地址的引用指针)和returnAddress类型(指向了一条字节码指令的地址),在编译期分配内存。

方法区

    类型信息:

             类型全名(完整有效名)、类型的父类型的全名(完整有效名)

             是类还是接口

             类修饰符

             直接接口的有序列表

    除此之外,还保存以下信息:

  1. 类型的常量池:jvm为每个已加载的类型都维护一个常量池。常量池就是这个类型用到的常量的一个有序集合,包括实际的常量(string, 
    integer, 和floating point常量)和对类型,域和方法的符号引用。池中的数据项象数组项一样,是通过索引访问的。 
    因为常量池存储了一个类型所使用到的所有类型,域和方法的符号引用,所以它在java程序的动态链接中起了核心的作用。

  2. 域(Field)信息:jvm必须在方法区中保存类型的所有域的相关信息以及域的声明顺序, 
    域的相关信息包括: 域名、域类型 、域修饰符(public, private,protected,static,final   volatile, transient的某个子集)

  3. 方法(Method)信息:jvm必须保存所有方法的以下信息,同样域信息一样包括声明顺序 、方法名 、方法的返回类型(或 void) 、方法参数的数量和类型(有序的) 、方法的修饰符(public, private, protected, static, final,synchronized, native, abstract的一个子集)除了abstract和native方法外,其他方法还有保存方法的字节码(bytecodes)操作数栈和方法栈帧的局部变量区的大小 

  4. 除了常量外的所有静态(static)变量:

    类变量(类变量被类的所有实例共享,即使没有类实例时你也可以访问它。这些变量只与类相关,所以在方法区中,它们成为类数据在逻辑上的一部分。在jvm使用一个类之前,它必须在方法区中为每个non-final类变量分配空间)。

    常量(被声明为final的类变量)的处理方法则不同,每个常量都会在常量池中有一个拷贝。non-final类变量被存储在声明它的 类信息内,而final类被存储在所有使用它的类信息内。

常见永久代内存溢出:OutOfMemoryError: PermGen

永久代存放Class及元数据信息(Meta),Class在Loader时放入PermGen space,该区域不会被GC在程序运行期回收,所以如果加载太多类可能导致该错误,由于在java8中永久内存移除堆内存到本地内存,所以该异常已基本不会出现。


本地方法栈:本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用非常类似,区别在于虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则是为虚拟机使用到的Native方法服务。


附录1:内存泄露和内存溢出区别?

    内存泄露:是指申请内存后,无法释放已申请的内存。

    内存溢出:指应用程序在申请内存时,无法分配足够的内存空间。

附录2:JVM参数配置表


参数名称

含义

默认值


-Xms

初始堆大小

物理内存的1/64(<1GB)

默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.

-Xmx

最大堆大小

物理内存的1/4(<1GB)

默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制

-Xmn

年轻代大小(1.4or lator)


注意:此处的大小是(eden+ 2  survivor space).jmap -heap中显示的New gen是不同的。

整个堆大小=年轻代大小 + 年老代大小 + 持久代大小.

增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8

-XX:NewSize

设置年轻代大小(for 1.3/1.4)



-XX:MaxNewSize

年轻代最大值(for 1.3/1.4)



-XX:PermSize

设置持久代(perm gen)初始值

物理内存的1/64


-XX:MaxPermSize

设置持久代最大值

物理内存的1/4


-Xss

每个线程的堆栈大小


JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右

一般小的应用,如果栈不是很深,应该是128k够用的大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。(校长)

threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"”

-Xss is translated in a VM flag named ThreadStackSize”

一般设置这个值就可以了。

-XX:ThreadStackSize

Thread Stack Size


(0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256  prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in  5.0 and earlier); all others 0.]

-XX:NewRatio

年轻代(包括Eden和两个Survivor)与年老代的比值(除去持久代)


-XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5

Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。

-XX:SurvivorRatio

Eden区与Survivor区的大小比值


设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10

-XX:LargePageSizeInBytes

内存页的大小不可设置过大,会影响Perm的大小


=128m

-XX:+UseFastAccessorMethods

原始类型的快速优化



-XX:+DisableExplicitGC

关闭System.gc()


这个参数需要严格的测试

-XX:MaxTenuringThreshold

垃圾最大年龄


如果设置为0的话,则年轻代对象不经过Survivor,直接进入年老代对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率

该参数只有在串行GC时才有效.

-XX:+AggressiveOpts

加快编译



-XX:+UseBiasedLocking

锁机制的性能改善



-Xnoclassgc

禁用垃圾回收



-XX:SoftRefLRUPolicyMSPerMB

每兆堆空闲空间中SoftReference的存活时间

1s

softly reachable objects will remain alive for some amount of time after  the last time they were referenced. The default value is one second of  lifetime per free megabyte in the heap

-XX:PretenureSizeThreshold

对象超过多大是直接在旧生代分配

0

单位字节新生代采用Parallel  Scavenge GC时无效

另一种直接在旧生代分配的情况是大的数组对象,且数组中无外部引用对象.

-XX:TLABWasteTargetPercent

TLABeden区的百分比

1%


-XX:+CollectGen0First

FullGC时是否先YGC

FALSE



附录3:并行收集器相关参数 


参数名称

含义

默认值


XX:+UseParallelGC

Full GC采用parallel MSC


选择垃圾收集器为并行收集器.此配置仅对年轻代有效.即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集.(此项待验证)

(此项待验证)

-XX:+UseParNewGC

设置年轻代为并行收集


可与CMS收集同时使用

JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值

-XX:ParallelGCThreads

并行收集器的线程数


此值最好配置与处理器数目相等同样适用于CMS

-XX:+UseParallelOldGC

年老代垃圾收集方式为并行收集(Parallel Compacting)


这个是JAVA 6出现的参数选项

-XX:MaxGCPauseMillis

每次年轻代垃圾回收的最长时间(最大暂停时间)


如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值.

-XX:+UseAdaptiveSizePolicy

自动选择年轻代区大小和相应的Survivor区比例


设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开.

-XX:GCTimeRatio

设置垃圾回收时间占程序运行时间的百分比


公式为1/(1+n)

-XX:+ScavengeBeforeFullGC

Full GC前调用YGC

TRUE

Do young generation GC prior to a full GC. (Introduced in 1.4.1.)

附录4:CMS相关参数 


参数名称

含义

默认值


-XX:+UseConcMarkSweepGC

使用CMS内存收集


测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明.所以,此时年轻代大小最好用-Xmn设置.???

-XX:+AggressiveHeap



试图是使用大量的物理内存

长时间大内存使用的优化,能检查计算资源(内存,处理器数量)

至少需要256MB内存

大量的CPU/内存,(在1.4.14CPU的机器上已经显示有提升)

-XX:CMSFullGCsBeforeCompaction

多少次后进行内存压缩


由于并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生"碎片",使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩,整理.

-XX:+CMSParallelRemarkEnabled

降低标记停顿



-XX+UseCMSCompactAtFullCollection

FULL GC的时候,对年老代的压缩


CMS是不会移动内存的,因此,这个非常容易产生碎片,导致内存不够用,因此,内存的压缩这个时候就会被启用。增加这个参数是个好习惯。

可能会影响性能,但是可以消除碎片

-XX:+UseCMSInitiatingOccupancyOnly

使用手动定义初始化定义开始CMS收集


禁止hostspot自行触发CMS GC

-XX:CMSInitiatingOccupancyFraction=70

使用cms作为垃圾回收

92

为了保证不出现promotion  failed(见下面介绍)错误,该值的设置需要满足以下公式CMSInitiatingOccupancyFraction计算公式

使用70%后开始CMS收集

-XX:CMSInitiatingPermOccupancyFraction

设置Perm Gen使用到达多少比率时触发

92


-XX:+CMSIncrementalMode

设置为增量模式


用于单CPU情况

-XX:+CMSClassUnloadingEnabled





附录5:其他JVM配置参数

 

参数名称

含义


-XX:+PrintGC


输出形式:

[GC 118250K->113543K(130112K), 0.0094143 secs]

[Full GC 121376K->10414K(130112K), 0.0650971 secs]

-XX:+PrintGCDetails


输出形式:[GC [DefNew:  8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K),  0.0124633 secs]

[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured:  112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K),  0.0436268 secs]

-XX:+PrintGCTimeStamps



-XX:+PrintGC:PrintGCTimeStamps


可与-XX:+PrintGC  -XX:+PrintGCDetails混合使用

输出形式:11.851: [GC  98328K->93620K(130112K), 0.0082960 secs]

-XX:+PrintGCApplicationStoppedTime

打印垃圾回收期间程序暂停的时间.可与上面混合使用

输出形式:Total time  for which application threads were stopped: 0.0468229 seconds

-XX:+PrintGCApplicationConcurrentTime

打印每次垃圾回收前,程序未中断的执行时间.可与上面混合使用

输出形式:Application  time: 0.5291524 seconds

-XX:+PrintHeapAtGC

打印GC前后的详细堆栈信息


-Xloggc:filename

把相关日志信息记录到文件以便分析.


与上面几个配合使用

-XX:+PrintClassHistogram

garbage collects before printing the histogram.


-XX:+PrintTLAB

查看TLAB空间的使用情况


XX:+PrintTenuringDistribution

查看每次minor GC后新的存活周期的阈值

Desired survivor size 1048576 bytes, new threshold 7 (max 15)

new threshold 7即标识新的存活周期的阈值为7

附录6:jmap –heap导出文件详解

using parallelthreads in the new generation.  ##新生代采用的是并行线程处理方式

usingthread-local object allocation.   

Concurrent Mark-SweepGC   ##同步并行垃圾回收

 

HeapConfiguration:  ##堆配置情况

  MinHeapFreeRatio = 40 ##最小堆使用比例

  MaxHeapFreeRatio = 70 ##最大堆可用比例

  MaxHeapSize      = 2147483648 (2048.0MB) ##最大堆空间大小

  NewSize          = 268435456(256.0MB) ##新生代分配大小

  MaxNewSize       = 268435456 (256.0MB) ##最大可新生代分配大小

  OldSize          = 5439488(5.1875MB) ##老生代大小

  NewRatio         = 2  ##新生代比例

  SurvivorRatio    = 8 ##新生代与suvivor的比例

  PermSize         = 134217728 (128.0MB)##perm区大小

  MaxPermSize      = 134217728 (128.0MB) ##最大可分配perm区大小

 

Heap Usage: ##堆使用情况

New Generation(Eden + 1 Survivor Space):  ##新生代(伊甸区 + survior空间)

  capacity = 241631232 (230.4375MB)  ##伊甸区容量

  used     = 77776272 (74.17323303222656MB) ##已经使用大小

  free     = 163854960 (156.26426696777344MB) ##剩余容量

  32.188004570534986% used ##使用比例

Eden Space: ##伊甸区

  capacity = 214827008 (204.875MB) ##伊甸区容量

  used     = 74442288 (70.99369812011719MB) ##伊甸区使用

  free     = 140384720 (133.8813018798828MB) ##伊甸区当前剩余容量

  34.65220164496263% used ##伊甸区使用情况

From Space:##survior1区

  capacity = 26804224 (25.5625MB) ##survior1区容量

  used     = 3333984 (3.179534912109375MB) ##surviror1区已使用情况

  free     = 23470240 (22.382965087890625MB) ##surviror1区剩余容量

  12.43827838477995% used ##survior1区使用比例

To Space:##survior2 区

   capacity= 26804224 (25.5625MB) ##survior2区容量

  used     = 0 (0.0MB) ##survior2区已使用情况

  free     = 26804224 (25.5625MB) ##survior2区剩余容量

   0.0%used ## survior2区使用比例

concurrentmark-sweep generation: ##老生代使用情况

  capacity = 1879048192 (1792.0MB) ##老生代容量

  used     = 30847928 (29.41887664794922MB) ##老生代已使用容量

  free     = 1848200264 (1762.5811233520508MB) ##老生代剩余容量

  1.6416783843721663% used ##老生代使用比例

Perm Generation:##perm区使用情况

  capacity = 134217728 (128.0MB) ##perm区容量

  used     = 47303016 (45.111671447753906MB) ##perm区已使用容量

  free     = 86914712 (82.8883285522461MB) ##perm区剩余容量

  35.24349331855774% used ##perm区使用比例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cfpl12011124

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值