导航:首页 > 数据分析 > jvm元数据区在哪里

jvm元数据区在哪里

发布时间:2023-03-31 11:17:37

1. jvm - 常用调优启动参数配置

可以看到堆内存为2G,新生代为768M老年代为1280M,新生代采用ParNew收集器
-XX:+UseConcMarkSweepGC:新生代使用ParNew回收器,老年代使用CMS
线程栈为512k(默认1024k调小可以增加创建线程数,增加并发量)
同时打印 GC 详细信息和打印 GC 发生时间,当发生OOM时,Dump文件到指定路径

栈空间参数设置
-Xss: 设置线程的最大银山碰栈空间,栈空间越大,方法的递归深度越大

方法区参数设置(方法区大小的参数设置跟jdk版本相关)
jdk1.6,jdk1.7设置方法区永久代的大小
-XX:PermSize=5M
-XX:MaxPermSize=5M 最大永久代的大小默认是64M
jdk1.8及以上,永久代被移除,取而代之的是元数据区,元数据区是一块堆外的直接内存
如果不指定大小,那么会耗尽所有可用的系统内存
-XX:MaxMetaspaceSize=60M 设置最大元数据的大小

堆设置
-Xms:初始堆大小
-Xmx:最大堆大小
-Xmn:设置新生代大小,设置较大的新生代大小会减小老年代大小,新生代的大小一般为堆空间的1/3
-XX:NewSize=n: 设置年轻代大小
-XX:NewRatio=n:设置年轻代和年老代的比值(老年代/新生代)。如:为3,表示年轻代与年老代比值为1:3
年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。

-Xmn,-XX:NewSize/-XX:MaxNewSize,-XX:NewRatio 3组参数都可以影响年轻代的大小,混合使用的情况下,优先级是什么?

1.高优先级:-XX:NewSize/-XX:MaxNewSize
2.中优先级:-Xmn(默认等效 -Xmn=-XX:NewSize=-XX:MaxNewSize=?)
3.低优先级:-XX:NewRatio
推荐使用-Xmn参数,原因是这个参数简洁,相当于一次设定 NewSize/MaxNewSIze而且两者相等,适用于生产环境。
-Xmn 配合 -Xms/-Xmx,即可将堆内存布局完成 -Xmn参数是在JDK 1.4 开始支持

下面两个参数配合使用,当系统发生堆空间不足时,会导出整个堆的信息,且导出到指定的文件中去,后面用MAT工具分析
-XX:HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=d:/a.mp
直接内存配置
-XX:MaxDirectMemorySize
设置直接内存大小,如果不设置,默认值为最大堆空间,即-Xmx指定的大小,当达到指定值时,
会触发垃圾回收,如果回收后也无法释放空间,那么将会抛出OOM

-XX:+UseSerialGC:新生代,老年代都使用串行收集器
-XX:+UseParNewGC:新生代使用ParNew收集器,老年代使用串锋谈行收集器Serial
(jdk9,10已经废除,因为ParNew只能和CMS收集器配合使用,而jdk9,10使用的默认收集器是G1)
-XX:+UseParallelGC:新生代使用ParallelGC,老年代使用串行收集器Serial

-XX:+UseParallelGC:新生代使用ParallelGC回收器,老年代使用串行回收器Serial
-XX:+UseParallelOldGC:新生代使用ParallelGC回收唯者器,老年代使用ParallelOldGc回收器

两个重要参数
-XX:MaxGCPasuseMillis:设置最大垃圾回收停顿时间,设置的过小,可能导致垃圾回收频率加大
-XX:GCTimeRatio:设置吞吐量大小,取值范围为0-100,系统回收垃圾的停顿时间花费不超过1/(1+n)%

设置线程数量
-XX:ParallelGCThreads

-XX:+UseConcMarkSweepGC:新生代使用ParNew回收器,老年代使用CMS
CMS默认启动的并发线程数量为(parallelGCTheads+3)/4

设置并发线程数
-XX:ConcGCThreads=n
-XX:ParallelGCThreads=n

设置老年代空间使用率达到多少时执行CMS垃圾回收
-XX: 默认值为68

碎片整理参数,如果碎片不整理,可能造成没达到阈值就会触发老年代垃圾回收
-XX:+UseCMSCompactAtFullCollection :在CMS垃圾收集完成之后,进行一次内存碎片整理
-XX:+CMSFullGCsBeforeCompaction=n :在n次CMS回收后进行一次内存碎片整理

使用CMS回收方法去的perm区,默认情况下,还需要触发一次FullGC
-XX:+CMSClassUnloadingEnabled

XX:UseG1GC 开启G1垃圾收集器

两个重要的参数
-XX:MaxGcPasuseMillis :指定目标最大停顿时间,如果停顿的时间过小,一次收集的区域数量也会变小
就会增加FullGC的可能

-XX:parallelGCThreads :设置并行回收的GC线程数量

-XX: :设置整个堆使用率达到多少时,触发并发标记的执行,默认是45

-XX:+PrintGC 在程序运行期间,只要遇到GC,就会打印GC情况
占用大小->gc后大小 GC消耗时间
jdk9,jdk10默认使用G1收集器,所以打印GC参数不同
-Xlog:gc

-XX:+PrintGCDetails 打印GC详细信息(JDK8,9,10建议使用-Xlog:gc*)
-XX:+PrintGCTimeStamps 打印分析GC发生的时间
-XX:+ 打印应用程序的执行时间
-XX:+PrintGCApplicationStoppedTime 打印GC产生停顿的时间
-Xloggc:/usr/local/log/gc.log 让gc日志打印在log文件夹下的gc文件中,因为默认情况下gc日志在控制台输出

栈上分配,逃逸分析(方法内的变量被外部引用)
允许对象直接在栈上进行分配,随线程停止而销毁,这样做可以加快分配速度,减少GC次数
栈空间较小,所以不适合大对象的栈上分配

-XX:+DoEscapeAnalysis 启用逃逸分析
-XX:+EliminateAllocations 开启标量替换(默认打开),允许对象打散分配在栈上
比如对象拥有id和name两个字段,那么这两个字段将会被视为两个独立的变量进行分配。
对象晋升
-MaxTenuringThreshold=n ,当对象经历了多少次GC次数后进入老年代
注意:大对象直接晋升到老年代
-PretenureSizeThreshold=n 这里的单位是字节,新生对象大于这个值的时候,会直接分配到老年代

1、对存活对象标注时间过长:比如重载了Object类的Finalize方法,导致标注Final Reference耗时过长;或者String.intern方法使用不当,导致YGC扫描StringTable时间过长。

2、长周期对象积累过多:比如本地缓存使用不当,积累了太多存活对象;或者锁竞争严重导致线程阻塞,局部变量的生命周期变长

当Eden区空间不足时,就会触发YGC。结合新生代对象的内存分配看下详细过程:

1、新对象会先尝试在栈上分配,如果不行则尝试在TLAB分配,否则再看是否满足大对象条件要在老年代分配,最后才考虑在Eden区申请空间。

2、如果Eden区没有合适的空间,则触发YGC。

3、YGC时,对Eden区和From Survivor区的存活对象进行处理,如果满足动态年龄判断的条件或者To Survivor区空间不够则直接进入老年代,如果老年代空间也不够了,则会发生promotion failed,触发老年代的回收。否则将存活对象复制到To Survivor区。

4、此时Eden区和From Survivor区的剩余对象均为垃圾对象,可直接抹掉回收。

此外,老年代如果采用的是CMS回收器,为了减少CMS Remark阶段的耗时,也有可能会触发一次YGC,这里不作展开。

大多数情况下,对象直接在年轻代中的Eden区进行分配,如果Eden区域没有足够的空间,那么就会触发YGC(Minor GC),YGC处理的区域只有新生代。因为大部分对象在短时间内都是可收回掉的,因此YGC后只有极少数的对象能存活下来,而被移动到S0区(采用的是复制算法)。当触发下一次YGC时,会将Eden区和S0区的存活对象移动到S1区,同时清空Eden区和S0区。当再次触发YGC时,这时候处理的区域就变成了Eden区和S1区(即S0和S1进行角色交换)。每经过一次YGC,存活对象的年龄就会加1。

下面4种情况,对象会进入到老年代中:

当晋升到老年代的对象大于了老年代的剩余空间时,就会触发FGC(Major GC),FGC处理的区域同时包括新生代和老年代。除此之外,还有以下4种情况也会触发FGC:

2. jvm堆内存和非堆内存(小白入门文,各博客视频基础总结)

一:堆内存和非堆内存定义
java虚拟机具有一个堆(Heap),堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是Java虚拟机启动时创建的。在JVM中堆之外的内u你成为非堆内存(Non-heap memory)。
堆内存以及相应垃圾回收算法
1.堆的大小可以固定,也可以扩大和缩小,堆内存不需要是连续空间。
2.对象创建后进入Eden。年轻代分为Eden和Survivor。Survivor由FromSpace和ToSpace组成。Eden区占大容量,Survivor占小容量,默认比例8:1:1。
MinorGC:采用复制算法。首先把Eden和ServivorFrom区域中存活的对象赋值到ServivorTo区域(如果对象年龄达到老年标准/ServivorTo位置不够了,则复制到老年代),同时对象年龄+1,然后清空Eden和ServivorFrom中的对象。然后ServivorTo和ServivorFrom互换。
3.老年代
老年代存放生命周期长的内存对象。
老年代对象相对稳定,所以不会频繁GC。在进行MajorGC前一般都先进行一次MinorGC,使新生代的对象进入老年代,导致空间不够用时才触发。当无法找到足够大的连续空间分配给新晋的对象也会提前触发MajorGC进行垃圾回收。
MajorGC:如果使用CMS收集器,采用标记-清除算法。首先扫描老年代,标记游笑孝所有可回收对象,标记完成后统一回收所有被标记对象。同时会产生不连续的内存碎片。碎片过多会导致以后程序运行需要分配较大对象时,无法找到足够的连续内存,而不得已再次出发GC。否则采用标记-压缩算法。
标记-压缩:在标记可回收对象后,将不可回收对象移向一端,然后清除标记对象。
当神稿老年代也满了装不下时,抛出OOM异常。
二:永久代
内存中永久保存的区域,主要存放Class和Meta(元数据)的信息,Class在被加载的时候被放入永久区域。他和存放实例的区域不同,GC不会再主程序运行期对永久区进行清理。所以也可可能导致永久代区域随着加载Class的增多而胀满,抛出OOM。
Java8中,永久代已经被移除,被一个成为“元数据区”(元空间)的区域所取代。
元空间的本质与永久代类似,都是JVM方法区的实现。不过元空间使用本地内存,永久代在JVM虚拟机中。因此,默认情况下,元空间的大小受本地内存限制。类的元数据放入native memory,字符串常量池和类的静态变量放入java堆中,这样可以加载多少类的元数据就不再由MaxPermSize控制,而是由系统实际可用空间控制。
1元空间解决了永久代的OOM问题,元数据和class对象在永久代容易出现性能问题和内存溢出。
2类的方法信息等比较难确定其大小,对于永久代的大小指定比较困难,小永久代溢出,大老年代溢出。
3永久代会为GC带来不必要的复杂度,回收效率低。
三:堆内存参数调优
1.-Xms 设置初始分配内存大小,默认物理内存1/64
2.-Xmx 设置最大分升碰配内存,默认物理内存1/4
long maxMemory = Runtime.getRuntime().maxMemory(); long totalMemory = Runtime.getRuntime().totalMemory(); System.out.println("最大分配内存"+maxMemory/(double)1024/1024+"MB "+maxMemory/(double)1024/1024/1024+"GB"); System.out.println("默认分配内存"+totalMemory/(double)1024/1024+"MB "+totalMemory/(double)1024/1024/1024+"GB");

3. java线程存放在jvm的哪个区域方法又存放在哪个区呢

聊到JAVA中的方法,大多数人对于方法存储在方法区还是栈区(虚拟机栈)是很迷茫的。其实方法是存在方法区的下面我们就细细说一下JVM中的 方法区 VS 栈区方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,方法编译出的字节码也是保存在这

4. jvm运行时数据区有哪些

JVM运行时数据区包括:Meta Space元空间(JDK1.8之前叫方法区或者永久代)、VM Stack虚宴消喊拟机栈、Native Method Stack本地方法栈桥铅、Heap Space堆晌野空间、Program Couter Register程序计数器。

5. 重新理解jvm运行时的内存分布(堆栈方法区交互)

栈堆方法区的交互关系

java栈存储的本地变量表,包括八种数据类型和引用类型,引用类型指向对象的地址,保存在reference,指向java堆,对象类型数据会保存变量名,变量类型,变量值等,这些会存在方法区中去查看(在初始化的时候)。

在java栈中会存放对象实例(s1),但是他对象旁汪实例中具体的数据会由java栈中的引用指向java堆中的地址,里面的对象实例数据存放(实例名,实例相关类型,元数据信息。。。。),而静态变量,常量,类加载后的信息等会存放在方法区,在运行时需要调用的时候去方法区取,所以方法区和java堆都是共享的。而java栈时线程独有的数据(包括程序计数器,本地方法栈)。

一个jvm实例,只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件之后,需要把类,方法,常量放到堆内存中,保存所有的引用类型的真实信息,以方便执行器执行。堆内存分为三部分。

(养老区就是老年代)

堆内存 逻辑上 分为三部:新生 +养老 +方法区

eden+survivor+Spaces(元空间或者叫方法区或者Perm)

Perm 永久存储区,是一个常驻内存的区域,用于存放jdk自身携带的Class,Interface的元数据,被装载进此区域的数据是不会被垃圾回收器回收的,只有关闭jvm后才会释放此区域所占用的内存。

如果出现OutOfMemoryReeor: PermGen space 说明java虚拟机堆永久带Perm内存设置不够,答袜一半出现这种情况,都是程序启动加载大量第三方jar呆滞的,

对于HotSpot虚拟机很多开发者习惯将方法区称之为永久代(Parmenent
Gen),永久代是方法区的一个实现,这是不对的,方法区是逻辑上的部分。在jdk7中已经将原本放在永久代的字符串常量池移走了。

常量池( Constant Pool Constant PoolConstant Pool Constant Pool Constant Pool )是方法区的一部分, Class Class文件除了有类的版本、 字段方法、接口等描述信息外,还有一项就是常量池这部分内容将在类加载后进入。

伊甸园区,所有对象刚new出来都会放在这里。

对象分两种:
1.如果是大对象直接分配在Old区。
2.如果禁言了逃逸分析,会运举仔在栈上分配。
以上两种都不符合,放入伊甸园区。(Eden区)

看java7中如图:

对比java8

6. JVM中常量池存放在哪里

java8之前:

java8之后:元数据区 Metaspace

由于 PermGen 内存管理的效果远没有达到预期,所以JCP已经着手去除PermGen的工作。在JDK7中,字符串常量已经从永局裤久代移除。现今 JDK8 中 PermGen 已经被彻底移除,取而代之的是metaspace数据区,使用native内存,申请和释放由虚拟机负责管理。

那么,JVM中常量池到底存放在哪里?

Java6和6之前,常量唤腊樱池是存放在方法和丛区(永久代)中的。

Java7,将常量池是存放到了堆中。

Java8之后,取消了整个永久代区域,取而代之的是元空间。 运行时常量池和静态常量池存放在元空间中,而字符串常量池依然存放在堆中。

7. 如何设置jvm伊甸区大小

一、设置方法区内存大小

1、方法区的大小不必是固定的,jvm可以根据应用的需要动态调整。

1.1、jdk7及以茄型前:

1、通过-XX:PermSize来设置永久代初始分配空间。默认值是20.75M。

2、-XX:MaxPermsize来设定永久代最大可分配空间。32位机器默认是64M,64位机器模式是82M。

3、当JVM加载的类信息容量超过了这个值,会报异常outofMemoryError:PermGenspace

1.2、jdk8及以后

1、元数据区大小可以使孝改用参数-XX:MetaspaceSize和-XX:MaxMetaspaceSize指定,替代上述原有的两个参数。

2、默认值依赖于平台。windows下,-XX:MetaspaceSize是21M,-XX:MaxMetaspaceSize 的值是-1,即没有限制。

3、与永久代不同,如果不指定大小,默认情况下,虚拟机会耗尽所有的可用系统内存。如果元数据区发生溢出,虚拟机一样会抛出异常outofMemoryError: Metaspace

4、-XX:MetaspaceSize:设置初始的元空间大小。对于一个64位的服务器端JVM来说,其默认的-XX:MetaspaceSize值为21MB。这就是初始的高水位线一旦触颤慎猜及这个水位线,Full GC将会被触发并卸载没用的类(即这些类对应的类加载器不再存活),然后这个高水位线将会重置。新的高水位线的值取决于GC后释放了多少元空间。如果释放的空间不足,那么在不超过MaxMetaspaceSize时,适当提高该值。如果释放空间过多,则适当降低该值。

5、如果初始化的高水位线设置过低,上述高水位线调整情况会发生很多次。通过垃圾回收器的日志可以观察到Full GC多次调用。为了

8. jvm的理解

1
JVM内存区域

我们在编写程序时,经常会遇到OOM(out of Memory)以及内存泄漏等问题。为了避免出现这些问题,我们首先必须对JVM的内存划分有个具体的认识。JVM将内存主要划分为:方法区、虚拟机栈、本地方法盯搏栈、堆、程序计数器。JVM运行时数据区如下:

1.1
程序计数器
程序计数器是线程私有的区域,很好理解嘛~,每个线程当然得有个计数器记录薯升当前执行到那个指令。占用的内存空间小,可以把它看成是当前线程所执行的字节码的行号指示器。如果线程在执行Java方法,这个计数器记录的是正在执行的虚拟机字节码指令地址;如果执行的是Native方法,这个计数器的值为空(Undefined)。

此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

1.2
Java虚拟机栈
与程序计数器一样,Java虚拟机栈也是线程私有的,其生命周期与线程相同。

如何理解虚拟机栈呢?

本质上来讲,就是个栈。里面存放的元素叫栈帧,栈帧好像很复杂的样子,其实它很简单!它里面存放的是一个函数的上下文,具体存放的是执行的函数的一些数据。执行的函数需要的数据无非就是局部变量表(保存函数内部的变量)、操作数栈(执行引擎计算时需要),方法出口等等。

执行引擎每调用一个函数时,就为这个函数创建一个栈帧,并加入虚拟机栈。换个角度理解,每个函数从调用到执行结束,其实是对应一个栈帧的入栈和出栈。

注意这个区域可能出现的两种异常:

一种是StackOverflowError,当前线程请求的栈深度大于虚拟机所允许的深度时,会抛出这个异常。制造这种异常很简单:将一个函数反复递归自己,最终会出现栈溢出错误(StackOverflowError)。

另一种异常是OutOfMemoryError异常,当虚拟机栈可以动态扩展时(当前大部分虚拟机都可以),如果无法申请足够多的内存就会抛出OutOfMemoryError,如何制作虚拟机栈OOM呢,参考一下代码:

这段代码有风险,可能会导致操作系统假死,请谨慎使用~~~

1.3
本地方法栈
本地方法栈与虚拟机所发挥的作用很相似,他们的区别在于虚拟机栈为执行Java代码方法服务,而本地方法栈是为Native方法服务。与虚拟机栈一样,本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。

1.4
Java堆
Java堆可以说是虚拟机中最大一块内存了。它是所有线程所共享的内存区域,几乎所有的实例对象都是在这块区域中存放。当然,随着JIT编译器的发展,所有对象在堆上分配渐渐变得不那么“绝对”了。

Java堆是垃圾收集器管理的主要区域。由于现在的收集器基本上采用的都是分代收集算法,所有Java堆可以细分为:新生代和老年代。在细致分就是把新生代分为:Eden空间、From Survivor空间、To Survivor空间。当堆无法再扩展时,会抛出OutOfMemoryError异常。

1.5
方法区
方法区存放的是类信息、常量、静态变量等。方法区是各个线程共享区域,很容易理解,我们在写Java代码时,每个线程度可以访问同一个类的静态变量对象。由于使用反射机制的原因,虚拟机很难推测那个类信息不再使用,因此这块区域的回收很难。另外,对这块区域主要是针对常量池回收,值得注意的是JDK1.7已经把常量池转移到堆里面了。同样,当方法区无法满足内存分配需求时,会抛出OutOfMemoryError。

制造方法区内存溢出,注意,必须在JDK1.6及之前版本才会导致方法区溢出,原因后面解释,执行之前,可以把虚拟机的参数-XXpermSize和-XX:MaxPermSize限制方法区大小数则老。

运行后会抛出java.lang.OutOfMemoryError:PermGen space异常。

解释一下,String的intern()函数作用是如果当前的字符串在常量池中不存在,则放入到常量池中。上面的代码不断将字符串添加到常量池,最终肯定会导致内存不足,抛出方法区的OOM。

下面解释一下,为什么必须将上面的代码在JDK1.6之前运行。我们前面提到,JDK1.7后,把常量池放入到堆空间中,这导致intern()函数的功能不同,具体怎么个不同法,且看看下面代码:

这段代码在JDK1.6和JDK1.7运行的结果不同。

JDK1.6结果是:false,false ,JDK1.7结果是true, false。

原因是:JDK1.6中,intern()方法会吧首次遇到的字符串实例复制到常量池中,返回的也是常量池中的字符串的引用,而StringBuilder创建的字符串实例是在堆上面,所以必然不是同一个引用,返回false。

在JDK1.7中,intern不再复制实例,常量池中只保存首次出现的实例的引用,因此intern()返回的引用和由StringBuilder创建的字符串实例是同一个。为什么对str2比较返回的是false呢?这是因为,JVM中内部在加载类的时候,就已经有"java"这个字符串,不符合“首次出现”的原则,因此返回false。

9. java中,静态方法被调用是,存储在内存的哪个区域是栈还是放大区还是两者都有

在JDK8之前,静态成员(静态变量和静态方法)都是存储在方法区(永久代)中的内静态区中(这容里指类被加载后,静态成员的存储位置)。但在JDK8之后,永久代被移除了,取而代之的是元空间(metaspace)。但元空间中存储的主要是.class文件的元数据信息,静态成员的存储位置由方法区转到了堆内存(heap)中。
不过,不管是JDK8,还是更早的版本中,静态方法的执行(不仅仅是静态方法,还有普通的成员方法)都是在栈内存(stack)中进行的。每个线程都会在栈内存中开辟一个栈,在调用方法时,对应的方法都会在执行这个方法的线程的栈中创建一个“栈帧”,栈帧中保存了局部变量表(基本数据类型和对象引用)、操作数栈、动态连接和返回地址等信息。等到方法执行完毕,栈帧被销毁,对应的内存也将被释放。

10. jvm堆内存区域包括哪些

根据《Java虚拟机规范》的规定,运行时数据区通常包括这几个部分:程序计数器(Program Counter Register)、Java栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)。

如上图所示,JVM中的运行时数据区应该包括这些部分。在JVM规范中虽然规定了程序在执行期间运行时数据区应该包括这几部分,但是至于具体如何实现并没有做出规定,不同的虚拟机厂商可以有不同的实现方式。

阅读全文

与jvm元数据区在哪里相关的资料

热点内容
86版本剑魂阴剑配装 浏览:119
苹果手机hone键怎么发光啊 浏览:275
公路测量什么地方需要特殊编程的 浏览:753
为什么vs不能用exe文件 浏览:166
win10怎么找组策略 浏览:263
孩子学吉码少儿编程有什么好处 浏览:806
w7没有自带截图工具 浏览:928
vba新建excel文件 浏览:172
少儿编程合作招生需要准备什么 浏览:334
word目录编辑域 浏览:660
linux查找特殊字符 浏览:451
linux安装solr 浏览:28
iphone系统文件越用越大 浏览:64
微信修改的文件在哪里设置密码 浏览:48
老版支付宝安卓下载手机版本 浏览:688
动画文件格式为 浏览:180
微信怎么改单 浏览:368
笔记本韩国网站怎么访问 浏览:574
sai透视教程 浏览:346
苹果6s64g的停产了吗 浏览:507

友情链接