深入理解java虚拟机JVM(上)
深入理解java虚拟机JVM(上)
链接:https://pan.baidu.com/s/1c6pZjLeMQqc9t-OXvUM66w
提取码:uwak
复制这段内容后打开百度网盘手机App,操作更方便哦
1. java的技术体系概述
1.1 java介绍
ava的体系结构规范:
- java编程语言
- java Class文件格式
- java API
- java VM
java VM
- JVM的核心组件:Class loader
- 执行引擎(解释器)-----> java进程启动
java编程语言的主要特性:纯面向对象的编程,多线程,结构化错误处理,自动垃圾收集,动态链接,动态扩展
java2 EE:
java 2 SE:JDK
- Open JDK,Oracle JDK
java 2 EE:JDK + 企业级类库
- Servlet,JSP,EJB,JMS,JMX,javaMall....
- 商业实现:Weblogic,WebSphere,Oc4j,tomcat(java实现阉割版)
Web Container :
- Servlet Container :Tomcat 3.x
实现:
商业版:
- WebSphere(IBM)
- Weblogic(Oracle)
- JBoss
开源实现:
- Tomcat:轻量级javaWeb服务器(servlet,jsp,jdk)
- Jetty
- Resin:重量级javaWeb服务器
1.2 java代码的编译与执行
1.3 java代码的类库调用过程
index.java --> javaC --> index.class --> class loader --> JVM
1.4 javaEE的处理流程
- JSP(java server pages):运行于服务端的java程序,遵循servlet格式标准。
- JS(javascript):网页中的脚本语言(html管理内容,css管理位置,js管理动作)
#Servlet格式:
JSP:
<html>
<title></title>
<body>
<h1>...<h1>
<%
...
java code here
...
%>
</body>
</html>
- 以上代码java编译器显然并不认识;
- 所以我们才需要基于Servlet,将其转换为纯java代码,格式为servlet;
- 如此一来java编译器才能认识,才能进行公共类的封装。
index.jsp --> Servlet(转译器) --> index_jsp.java--> javaC(编译器) -->index_jsp.class --> class loader(加载器) -->JVM
1.5 Tomcat架构分析
Tomcat官方网站 http://tomcat.apache.org
#tomcat组件:
<Server>
<Service>
<Connector/>
<Connector/>
<Engine>
<Host>
<Context/>
...
</Host>
<Host>
</Host>
...
</Engine>
</Service>
</Server>
每个组件都是由“类”实现,此些组件可分为如下几类:
- 顶级组件:Server
- 服务组件:Service
- 连接器组件:http,https,ajp
- 容器类:Engine,Host,Context
- 被嵌套类组件:valve,logger,realm,loader manager
- 集群类组件:listener...
2. JVM执行分析
2.1 Java内存模型概述
运行时数据区之中内存的分配一共有五块:
- 堆内存(Heap):保存真正的程序的数据的部分;
- java栈(Stack):保存堆内存的地址,基本数据,方法的执行;
- 方法区:保存所有的方法的具体操作,该区域属于共享;
- 程序计数器:这是一块很小内存,只是做一个数据的计数;
- 本地方法栈:该栈之中说保存的都是操作系统的原生函数。
在整个的JVM内存组成过程中,栈内存是一个非常重要的概念,因为在该内存之中,他需要保存的是一组内容。
栈是运行时的单位,而堆是存储的单元
- 栈因为是运行单位,里面存储的信息都是跟当前线程(或程序)相关的信息。包括局部变量,程序运行状态,方法返回值等;
- 堆知识保存对象信息
栈内存是线程私有的,其生命周期和线程相同;
虚拟机栈描述的是Java方法执行的内存模型:执行一个方法时会产生一个栈帧,随后将其保存到栈(后进先出)的顶部,方法执行完毕后会自动将此栈帧进行出栈。顶部的栈帧就表示的是当前方法;
- 如果请求的栈的深度过大,虚拟机可能会抛出StackOverflowError异常;
- 如果虚拟机的实现中允许,虚拟机栈动态扩展,当内存不足以扩展栈的时候,会抛出OutOfMemoryError异常。
Java虚拟机栈----栈帧(Stack Frame),Java虚拟机栈会存放的是多个栈帧,包括如下主要组成部分- 局部变量表(Local Variables):方法的局部变量或形参,其以变量槽(solt)为最小单位,只允许保存32位长度的变量,如果超过32位则会开辟两个连续的solt(64位长度,long和double);
- 操作数栈(Operand Stack):表达式计算在栈中完成;
- 指向当前方法所属的类的运行时常量池的引用(Reference to runtime constant pool):引用其他类的常量或者使用String池中的字符串;
- 方法返回地址(Return Address):方法执行完后需要返回调用此方法的位置,所以需要在栈帧中保存方法返回地址;
2.2 java对象的访问模式
在很多面向对象的语言里,都会存在一个叫做句柄的概念,而Java是没有提供有句柄的概念。这个概念的产生主要是在引用数据类型上,例如我们利用Python的句柄去打开一个文件,代码示例如下所示:
#句柄在python中的使用
f = open("test") #创建文件句柄以相对路径打开文件(f ===> 指代文件的内存地址)
first_line = f.readline() #读取文件内容的一行,并赋值
print (first_line) #打印文件内容第一行
for num in range(4) : #循环迭代4次
print (f.readline()) #再读一行继续打印(重复4次)
f.close() #关闭文件
#对象(句柄)在java中的使用
Object obj #声明对象,实际上只是表示一个本地的引用,那么这个本地的引用本身一定会保存一个堆内存的地址,在这之中还会包含一个本地变量表的概念,也就是说,引用类型通过本地变量表才能找到一个具体的堆内存的引用数据。
obj = new Object() #实例化对象,实例化对象就会开辟堆内存空间;在这个过程中有两种做法:通过句柄进行访问;直接指针访问;
2.3 JVM的规范标准
现在最具有权威性的只有Oracle一家公司,因为拥有两个虚拟机的版权;
那么,我们现在用的虚拟机到底是什么版本呢?
#在安装了jdk环境的系统上查看
[root@Tomcat-Jvm ~]# which java
/usr/jdk/bin/java
[root@Tomcat-Jvm ~]# java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
- 当前虚拟机采用的是混合模式mixed mode(解释与编译);
- 这个的编译并不是像javaC一样将.java编译成.class那么简单;
- 这里面包含了一个JIT(Just Is Time,即时编译);
- VM在运行的时候,class loader只是把*.class文件做了一个简单的加载过程;
- 真正运行*.class是JVM的执行引擎在执行的过程中动态完成的。
- 当然,我们也可以改变这种模式,如下所示:
#JVM虚拟机的纯解释模式
[root@Tomcat-Jvm ~]# java -Xint -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, interpreted mode)
#JVM虚拟机的纯编译模式
[root@Tomcat-Jvm ~]# java -Xcomp -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, compiled mode)
3. JVM内存模型与垃圾收集
- JVM的垃圾收集主要指的是堆内存空间,那么在我们每一次执行GC的时候需要区分出哪些堆内存需要被回收,哪些不需要被回收,所以为了整体的回收处理方便,JVM将堆内存分为如下的几个组成部分,而这几个组成部分你还需要去考虑JDK版本。
- 现在的JVM内存划分就必须考虑JDK1.8以前和JDK1.8以后的问题;
3.1 Java堆内存模型
如果简化点来理解的话:
- 新生代:那些刚刚创建的对象,刚刚创建的对象有可能会存在有许多的垃圾对象,那么这些对象是应该被优先回收的;
- 老年代:老不死的那类对象,经过了很多次的清理之后你发现该对象依然有用;
- 永久代:JAVA的intern()方法进行入池的对象实际上就在永久代中,永久代不会被回收;正因为它的存在本身属于一个BUG性的存在,因此在JDK1.8之后,将它更换为了元空间(电脑的直接内存)。
- 在整个内存的组成过程之中每一代的内存都会有一个伸缩区,那么该区域就可以由JVM根据空间的使用情况动态扩充;
- 当我们适当合理的设置了伸缩区的内存大小之后,就可以得到良好的性能提升,也就是说最容易的性能提升就是改变伸缩区的内存大小设置。
3.2 Java对象创建与垃圾回收流程
在Java之中支持有GC的概念,那么GC有两种调用形式:自动调用,手工调用(Runtime.getRuntime().gc())。但一般情况下,我们很少用手工调用GC的方式。那么什么时候我们会进行自动的GC调用呢?这里面就牵扯到了两类的GC操作环境
- 当我们的程序中需要产生新的实例化对象(关键字new,对象克隆,反射实例化)的时候那么就一定要进行内存空间的开辟,所以此时需要申请新的内存空间;
- 新对象要申请的对象空间默认都是在伊甸园区(新生)进行开辟,所以首先需要判断伊甸园区是否有空余的内存空间,如果有,那么直接在伊甸园区开辟新的堆内存空间,此时不会发生有GC处理;
- 如果新对象无法在伊甸园空间申请出新的空间,那么就表示现在的伊甸园的内存空间不足,不足就需要将那些无用的新对象进行回收(Minor GC),当回收完成后要继续判断该空间是否可以容纳新的对象,如果可以容纳,则开辟新的空间保存新的对象;
- 如果此时伊甸园区即使执行了Minor GC之后发现依然没有可以被回收的对象,那么这个时候将继续判断存活区是否有空间(存活区一般与伊甸园区比率:1:1:8),如果存活区有空余空间,则将那些活跃的伊甸园区的部分对象直接保存给存活区,就相当于伊甸园区可以腾出部分的空间(这个空间非常小)来,供新对象进行使用;
- 如果此时存活区依然满了(空间不足),则继续向老年代进行内存空间的申请,首先会判断老年代的空间是否空余,如果有空余的空间,则将存活区中的活跃对象保存在老年代,而后存活区得到了空间释放,伊甸园区也就得到了空间释放,从而伊甸园区就可以开辟新的内存空间来保存新的对象;
- 如果现在老年区也是满的,那么这个时候就会执行FULL GC(完全GC,Major GC)进行老年代的内存释放,如果可以释放成功,则进行对象的保存,如果释放不成功则表示已经没有无用的内存空间了,那么就会抛出OOM错误(OutOfMemoryError)。
3.2.1 请问自动的GC什么时候触发?
GC的触发有两类:
- Minor GC:发生在新生代内存空间,当新生代内存空间不足时会进行触发,释放新生代中不活跃的对象;
- Full GC:发生在老年代内存空间,当老年代的空间不足时会自动触发Full GC,如果触发Full GC之后内存空间依然不足,则会产生OutOfMemoryError的错误提示信息;
3.3 Java堆内存基础调整策略(JVM基础优化策略)
GC 虽然可以进行内存空间的释放,但同时频繁的GC一定会影响系统性能,那么如何才可以不频繁的发生GC呢?
- 内存越大GC发生的频率就越低,你的系统的性能一定就越高效。
如果我们给用户使用的内存空间留有伸缩区,那么- 可用内存空间不足,就会判断伸缩区是否有空间,而后部分开辟伸缩区的空间。那么这种伸缩区的开辟与回收就有可能产生性能下降。
如果说现在取消掉伸缩区的概念,让初始化的内存就是最大的可用内存空间,这样就可以实现JVM的性能调整,避免每次gc后都重复性调整堆的大小,可以让整个的代码的执行速度得到提升。
例如:-Xms16g -Xmx16g 将堆内存初始大小和堆内存最大大小设成一样,如此就把“伸缩区”给取消掉了
3.3.1 Tomcat堆内存调优实操演示
#在一台启动了tomcat的虚拟机上进行如下操作(未调优前
[root@Tomcat-Jvm ~]# pgrep java #查看tomcat的pid号
7862
[root@Tomcat-Jvm ~]# jmap -heap 7862 #通过jmap命令追踪java进程的堆信息
Attaching to process ID 7862, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.60-b23
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration: #堆内存初始化配置
MinHeapFreeRatio = 40 #JVM堆最小空闲比率
MaxHeapFreeRatio = 70 #JVM堆最大空闲比率
MaxHeapSize = 255852544 (244.0MB) #JVM堆的最大大小
NewSize = 5570560 (5.3125MB) #新生代的堆内存默认大小
MaxNewSize = 85262336 (81.3125MB) #新生代的堆内存最大大小
OldSize = 11206656 (10.6875MB) #老年代的堆内存最大大小
NewRatio = 2 #新生代和老年代的大小比率(新生代:老年代=1:2)
SurvivorRatio = 8 #新生代中eden区和存活区的大小比值(eden:S0:S1=8:1:1)
MetaspaceSize = 21807104 (20.796875MB) #元空间的默认大小
CompressedClassSpaceSize = 1073741824 (1024.0MB) #类指针压缩空间大小,默认1G
MaxMetaspaceSize = 17592186044415 MB #元数据最大值,超过此值会触发FULL GC,受限与系统内存大小
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space): #新生代对内存统计
capacity = 8257536 (7.875MB)
used = 5357464 (5.109275817871094MB)
free = 2900072 (2.7657241821289062MB)
64.87969292534723% used
Eden Space:
capacity = 7340032 (7.0MB)
used = 4439968 (4.234283447265625MB)
free = 2900064 (2.765716552734375MB)
60.48976353236607% used
From Space:
capacity = 917504 (0.875MB)
used = 917496 (0.8749923706054688MB)
free = 8 (7.62939453125E-6MB)
99.99912806919643% used
To Space:
capacity = 917504 (0.875MB)
used = 0 (0.0MB)
free = 917504 (0.875MB)
0.0% used
tenured generation: #老年代堆内存统计
capacity = 18305024 (17.45703125MB)
used = 14210536 (13.552223205566406MB)
free = 4094488 (3.9048080444335938MB)
77.6318894747147% used
9903 interned Strings occupying 857912 bytes.
#进行tomcat的基础堆内存参数调优
#调优tomcat的java内存需要在/usr/tomcat/bin/catalina.sh文件中加入参数
[root@Tomcat-Jvm bin]# vim catalina.sh
[root@Tomcat-Jvm bin]# sed -n '121p' catalina.sh
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1024m -Xmx1024m"
#重启动tomcat
[root@Tomcat-Jvm ~]# /usr/tomcat/bin/shutdown.sh
[root@Tomcat-Jvm ~]# /usr/tomcat/bin/startup.sh
#再次最终java进程的堆信息
[root@Tomcat-Jvm ~]# pgrep java
7933
[root@Tomcat-Jvm ~]# jmap -heap 7933
Attaching to process ID 7933, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.60-b23
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 1073741824 (1024.0MB)
NewSize = 357892096 (341.3125MB)
MaxNewSize = 357892096 (341.3125MB)
OldSize = 715849728 (682.6875MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 322109440 (307.1875MB)
used = 137906424 (131.51781463623047MB)
free = 184203016 (175.66968536376953MB)
42.81353070558876% used
Eden Space:
capacity = 286326784 (273.0625MB) #eden+两个存活区大小刚好为MaxNewSize大小,没有伸缩区了
used = 137906424 (131.51781463623047MB)
free = 148420360 (141.54468536376953MB)
48.163997120157646% used
From Space:
capacity = 35782656 (34.125MB)
used = 0 (0.0MB)
free = 35782656 (34.125MB)
0.0% used
To Space:
capacity = 35782656 (34.125MB)
used = 0 (0.0MB)
free = 35782656 (34.125MB)
0.0% used
tenured generation:
capacity = 715849728 (682.6875MB)
used = 0 (0.0MB)
free = 715849728 (682.6875MB)
0.0% used
9909 interned Strings occupying 858528 bytes.
3.3.2 项目中如何对java(JVM)进行调优?
在堆内存之中会存在有一个伸缩区的概念。
- 默认情况下最大可用内存为整体内存的四分之一;
- 默认使用的内存为整体可用内存的六十四分之一;
- 这时候只需要避免伸缩区的频繁变更,就可以提升程序的性能。
- 可以在程序执行的时候使用“-Xmx”设置最大可用内存空间大小;
- 可以在程序执行的时候使用“-Xms”设置初始化内存空间大小;
- 将这两个内容设置为一样的空间大小,就可以提升JVM的运行性能
3.4 新生代
新生代主要分为两个区域
- 伊甸园区
- 存活区
所有新创建的对象都会存活在伊甸园区,但是伊甸园区保存的空间一定是最大的,毕竟产生新对象的几率是很高的,在伊甸园区里面由于里面的对象经常可能只是临时创建,所以拥有一个Minor GC的操作处理,而经过多次的Minor GC后依然被保留下来的对象就认为该对象不应该被回收,则将此对象保存到存活区之中。
存活区一共分为两类:
- 存活0区(S0区,From Space)
- 存活1区(S1区,To Space)
这两个存活区主要是负责对象的晋级,向老年代进行晋级,并且这两个存活区有一块是专门负责对象回收的,因此有一块内存空间总是空的。(一个负责晋升,一个负责回收)。由于伊甸园区保存的数据对象一般比较多,所以默认的比率8:1:1。
3.4.1 新生代GC算法----复制算法(Copying)
算法:复制采用的方式为从根集合扫描出存活的对象,并将找到的存活对象复制到一块新的完全未使用的空间中。
下图红色部分为不存活对象所占内存空间,绿色为存活对象所占内存空间;
在进行GC之前一定要先发生一次全对象的扫描处理操作,通过扫描才可以知道哪些对象是垃圾空间
3.4.2 新生代中的算法优化
在实际运行中,由于Eden区总是会保存大量的新生对象,所以HotSpot虚拟机为了可以加快此空间的内存分配,而使用了两种技术。
- BTP(Bump-The-Pointer)
- TLAB(Thread-Local Alloction Buffers)
(1)BTP(Bump-The-Pointer)
虽然BTP的做法可以极大提高内存分配的速度;但堆内存和方法区都是线程共享的,在java多线程的情况下,线程间如果同时都要向Eden存入对象,那么就会产生冲突
(2)TLAB(Thread-Local Alloction Buffers)
- TLAB这种算法既解决了内存分配速度问题还解决了线程间冲突的问题;
- 但是这种算法会产生内存碎片(已经占用,但未存入对象);
- 而且如果Eden区为每个线程开辟的数据块过大,那么就会影响程序多线程的能力;
- 因此每个线程在Eden中的线程栈的大小,是需要我们进行调优的。
3.4.3 新生代内存参数调整
3.4.4 新生代堆内存参数调优实操演示
[root@Tomcat-Jvm bin]# pwd
/usr/tomcat/bin
[root@Tomcat-Jvm bin]# sed -n '121p' catalina.sh #源参数
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1024m -Xmx1024m"
[root@Tomcat-Jvm bin]# vim catalina.sh
[root@Tomcat-Jvm bin]# sed -n '121p' catalina.sh #现参数
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1024m -Xmx1024m -Xmn500m -Xss256k"
#重启动tomcat
[root@Tomcat-Jvm bin]# pgrep java
7631
[root@Tomcat-Jvm bin]# kill -9 7631
[root@Tomcat-Jvm bin]# sh startup.sh
[root@Tomcat-Jvm bin]# pgrep java
7734
[root@Tomcat-Jvm bin]# pgrep java
7734
[root@Tomcat-Jvm bin]# jmap -heap 7734
Attaching to process ID 7734, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.60-b23
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 1073741824 (1024.0MB)
NewSize = 524288000 (500.0MB)
MaxNewSize = 524288000 (500.0MB)
OldSize = 549453824 (524.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 471859200 (450.0MB)
used = 168826264 (161.0052719116211MB)
free = 303032936 (288.9947280883789MB)
35.77894931369357% used
Eden Space:
capacity = 419430400 (400.0MB)
used = 168826264 (161.0052719116211MB)
free = 250604136 (238.9947280883789MB)
40.25131797790527% used
From Space:
capacity = 52428800 (50.0MB)
used = 0 (0.0MB)
free = 52428800 (50.0MB)
0.0% used
To Space:
capacity = 52428800 (50.0MB)
used = 0 (0.0MB)
free = 52428800 (50.0MB)
0.0% used
tenured generation:
capacity = 549453824 (524.0MB)
used = 0 (0.0MB)
free = 549453824 (524.0MB)
0.0% used
9870 interned Strings occupying 856216 bytes.
3.5 老年代
- 一个对象要想真正的活到老年代实在是太难了,因为现在的程序属于多线程访问,所有的业务操作的对象都是针对于线程操作的,那么所有的线程在整体的操作过程中时间都是非常短的。那么这些对象往往都在新生代中开辟,很少能跑到老年代中。
- 老年代空间的主要目的是用于存储由Eden发送来的对象,一般在经历好几次“Minor GC”还会被保存下来的对象,才会被复制到老年代,一般老年代的内存空间大小会设置的比新生代要大,这样就可以存放更多的对象,同时在老年代中执行GC的次数也相对较少,当老年代内存不足时会自动执行“FULL GC”(也叫做“Major GC”)
3.5.1 老年代GC算法1----标记-清除(Mark-Sweep)
算法:标记-清除采用的方式为从根集合开始扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未标记的对象,并进行回收。
优缺点:在空间中存活对象较多的情况下较为高效,但由于该算法为直接回收不存活对象所占用的内存,因此会造成内存碎片
3.5.2 老年代GC算法2----标记-压缩(Mark-Compact)
算法:标记阶段与“标记-清除”算法相同,但在清除阶段有所不同。在回收不存活对象所占用的内存空间后,会将其他所有存活对象都往左端空闲的空间进行移动,并更新引用其对象指针。
优缺点:在“标记-清除”的基础上还需要进行对象移动,降低性能,成本相对较高,好处则是不产生内存碎片。
3.5.3 老年代内存参数调整
- 默认情况下,所有的对象都会通过新生代进行创建,而后经过不断的Minor GC之后要将其保存在老年代之中,但是如果现在有些对象的内容特别庞大。那么就建议不经过新生代而将其直接保存到老年代之中,就可以设置-XX:PretenureSizeThreshold=512K参数
- 一般一个良好的程序开发,是不可能出现对象过大的问题的。如果这种情况过多,就会造成老年代空间占满而触发FULL GC,一旦进行FULL GC那么持续时间会很长,对性能的影响很大。
3.6 永久代(JDK1.8后被废除了)
- 永久代是在JDK1.8以前的一个bug性的存在,其核心的本质在于:该区域中的对象不会被回收。当时简单的理解就是方法区就是永久代。
- 我们知道HotSpot虚拟机规范之中是存在有永久代概念的,但是BEA和IBM的虚拟机之中是不包含永久代概念的,Oracle公司现在将HotSpot中的永久代取消了,那么就意味着它现在希望可以将HotSpot与JRockit两个虚拟机的规范进行合并。
3.6.1 永久代内存参数调整(设置也已经没用了)
3.7 元空间
从JDK1.8开始正式取消了永久代之后,取而代之的就是元空间(MetaSpace),所谓的元空间的本质指的就是本机的物理内存,其作用和永久代相同。但是元空间和永久代最大的区别:元空间用的是物理内存(受到本机的物理内存限制),而永久代是JVM的内存空间,本身受到JVM的限制。
3.7.1 元空间的内存参数调整
基本上并不需要做调整
3.8 关于java的堆内存溢出(java.lang.OutOfMemoryError)
java的OOM报错有三种情况:
- java的堆内存溢出(java heap space)
- 永久代溢出(PermGen space)
- 元空间溢出(Meta space)
3.8.1 请问是否知道什么叫OOM?什么情况下会出现?
OutOfMemoryError:指的是内存溢出问题,内存的溢出需要考虑以下情况
- java的堆内存溢出(java heap space):往往出现在Full GC失败之后;
- 永久代溢出(PermGen space):一个方法中出现的内存溢出;
- 元空间溢出(Meta space):分配的物理内存不足,或者数据量高于物理内存。
深入理解java虚拟机JVM(上)的更多相关文章
- 深入理解JAVA虚拟机JVM
深入理解JAVA虚拟机JVM Java 虚拟机(Java virtual machine,JVM)是运行 Java 程序必不可少的机制.java之所以能实现一次编写到处执行,也就是因为jVM.原理:编 ...
- 深入理解java虚拟机JVM(下)
深入理解java虚拟机JVM(下) 链接:https://pan.baidu.com/s/1c6pZjLeMQqc9t-OXvUM66w 提取码:uwak 复制这段内容后打开百度网盘手机App,操作更 ...
- 什么是HotSpot VM & 深入理解Java虚拟机 JVM
参考 http://book.2cto.com/201306/25434.html 另外,这篇文章也是从一个系列中得出的: <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)> ...
- 理解JAVA虚拟机(上)
2016-04-16 23:10:50 在这里,我们进一步认识JAVA及JAVA虚拟机,包括它的体系结构和垃圾回收机制等,并通过虚拟机监控工具进行简单的性能调优. 一. JVM相关概念 ...
- 深入理解Java虚拟机-JVM运行时数据区域
一.运行时数据区域 1.程序计数器 程序计数器( Program Counter Register) 是一块较小的内存空间, 它可以看作是当前线程所执行的字节码的行号指示器. Java虚拟机的多线程是 ...
- 深入理解Java虚拟机—JVM内存结构
1.概述 jvm内存分为线程共享区和线程独占区,线程独占区主要包括虚拟机栈.本地方法栈.程序计数器:线程共享区包括堆和方法区 2.线程独占区 虚拟机栈 虚拟机栈描述的是java方法执行的动态内存模型, ...
- 《深入理解Java虚拟机:JVM高级特性与最佳实践》【PDF】下载
<深入理解Java虚拟机:JVM高级特性与最佳实践>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062566 内容简介 作为一位 ...
- JVM | 第1部分:自动内存管理与性能调优《深入理解 Java 虚拟机》
目录 前言 1. 自动内存管理 1.1 JVM运行时数据区 1.2 Java 内存结构 1.3 HotSpot 虚拟机创建对象 1.4 HotSpot 虚拟机的对象内存布局 1.5 访问对象 2. 垃 ...
- 《深入理解 java虚拟机》学习笔记
java内存区域详解 以下内容参考自<深入理解 java虚拟机 JVM高级特性与最佳实践>,其中图片大多取自网络与本书,以供学习和参考.
随机推荐
- Ubuntu18.04+CUDA9.0+cuDNN7.1.3+openface安装总结
目录 前言 编译工具CMake C++标准库安装 下载OpenFace代码 OpenCV安装 luarocks-Lua 包管理器,提供一个命令行的方式来管理 Lua 包依赖.安装第三方 Lua 包等功 ...
- showmount - 显示关于 NFS 服务器文件系统挂载的信息
总览 /usr/sbin/showmount [ -adehv ] [ --all ] [ --directories ] [ --exports ] [ --help ] [ --version ] ...
- ARM指令adr adrl ldr mov
ADR是一条小范围的地址读取伪指令,它将基于PC的相对偏移的地址值读到目标寄存器中.格式:ADR register,exper. 编译源程序时,汇编器首先计算当前PC值(当前指令位置)到exper的距 ...
- Educational Codeforces Round 69 E - Culture Code (最短路计数+线段树优化建图)
题意:有n个空心物品,每个物品有外部体积outi和内部体积ini,如果ini>outj,那么j就可以套在i里面.现在我们要选出n个物品的一个子集,这个子集内的k个物品全部套在一起,且剩下的物品都 ...
- [HTML知识体系]语义化标签概论
1.什么是语义化 语义化(Semantic)在HTML5中被大量提起,就是语义化标签向浏览器和开发者展示了它所包裹内容的类型与意思,可是至今我看了好多代码,HTML5新增的语义化标签的使用率还是挺低的 ...
- diff算法(核心)
ps:大致转载知乎文章 vue和react的虚拟dom都采用类似的diff算法,核心大概可以归为两点 1,两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构: 2,同一层级的一组节点, ...
- python plotly 使用教程
1.plotly介绍 lotly的Python图形库使互动的出版质量图表成为在线. 如何制作线图,散点图,面积图,条形图,误差线,箱形图,直方图,热图,子图,多轴,极坐标图和气泡图的示例. 推荐最好使 ...
- linux安装apue.3e
(1)下载源代码,可以去官网下载:http://apuebook.com/code3e.html (2)解压缩源代码文件:tar -zxvf src.3e.tar.gz (3) 安装静态链接库:sud ...
- php time()函数 语法
php time()函数 语法 time()函数怎么用? php time()函数用来返回当前时间的unix时间戳.语法是time(),返回自从 Unix 纪元(格林威治时间 1970 年 1 月 1 ...
- haproxy笔记
haproxy安装.启动.日志配置 方法1:#安装 yum install haproxy -y #日志配置 sed -i 's/^#$ModLoad imudp/$ModLoad imudp/g' ...