JVM结构和调优总结

以sun的hotspot虚拟机为基础

 

 

最好的三篇文章(后续翻译补充)

http://blog.jamesdbloom.com/JVMInternals.html

http://stackoverflow.com/questions/36898701/how-does-java-jvm-allocate-stack-for-each-thread

http://crunchify.com/jvm-tuning-heapsize-stacksize-garbage-collection-fundamental/

http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html

 

1、hotspot虚拟机结构

85e99d75-499b-33fb-b191-648058d501c6

最上层:javac编译器将编译好的字节码class文件,通过java 类装载器 执行机制,把对象或class文件 存放在 jvm划分内存区域

中间层:从左至右  方法区(持久代也叫非堆)、堆(共享,GC回收对象区域)、栈、程序计数器和寄存器、本地栈(私有)

最下层:jvm最核心两块 JIT(just in time)即时编译器 和 GC(Garbage Collection,垃圾回收器)

 

2、JVM堆模型

0_1325814932X3Ts

老生代= old space

新生代= eden+Survivor space =eden+(From space + to space)

 

HotSpot虚拟机GC算法采用分代收集算法(http://lhc1986.iteye.com/blog/1421832):

1、一个人(对象)出来(new 出来)后会在Eden Space(伊甸园)无忧无虑的生活,直到GC到来打破了他们平静的生活。GC会逐一问清楚每个对象的情况,有没有钱(此对象的引用)啊,因为GC想赚钱呀,有钱的才可以敲诈嘛。然后富人就会进入Survivor Space(幸存者区),穷人的就直接kill掉。

2、并不是进入Survivor Space(幸存者区)后就保证人身是安全的,但至少可以活段时间。GC会定期(可以自定义)会对这些人进行敲诈,亿万富翁每次都给钱,GC很满意,就让其进入了Genured Gen(养老区)。万元户经不住几次敲诈就没钱了,GC看没有啥价值啦,就直接kill掉了。

3、进入到养老区的人基本就可以保证人身安全啦,但是亿万富豪有的也会挥霍成穷光蛋,只要钱没了,GC还是kill掉。

 

3、java内存模型

11

Java内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存(可以与前面讲的处理器的高速缓存类比),线程的工作内存中保存了该线程使用到的变量到主内存副本拷贝,线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递均需要在主内存来完成,线程、主内存和工作内存的交互关系如下图所示,和上图很类似。

工作内存是什么,数据存在哪里?
     1、java内存模型的抽象概念
     2、并不一定在堆中,可能在cpu中的物理cache

JMM提供的只是一个抽象的概念,具体的实现由各个JVM来自己实现,虚拟机规范只是定义了对应的操作原语

be87523a50083ebbbd8fa83649568e48_r

运行时内存模型,分为线程私有和共享数据区两大类,其中线程私有的数据区包含程序计数器、虚拟机栈、本地方法区,所有线程共享的数据区包含Java堆、方法区,在方法区内有一个常量池
内存分为线程私有和共享两大类:

(1)线程私有区,包含以下3类: 
程序计数器,记录正在执行的虚拟机字节码的地址; 
虚拟机栈:方法执行的内存区,每个方法执行时会在虚拟机栈(stack)中创建栈帧(frames);java的栈和帧在内存中不是连续的,珍可以分布在连续的栈中,也可以分布在堆中。栈上的一处分析是分配局部变量的时候,如果局限于方法内部,如果空间足够在栈上分配,这样是为了加速minor gc。
本地方法栈:虚拟机的Native方法执行的内存区; 

(2)线程共享区,包含以下2类 
Java堆:对象分配内存的区域; 
方法区:存放类信息、常量、静态变量、编译器编译后的代码等数据; 
常量池:存放编译器生成的各种字面量和符号引用,是方法区的一部分。 

楼主提到的Java栈,一般而言是指图中的虚拟机栈,在代码中的方法调用过程中,往往需要从一个方法跳转到另一个方法,执行完再返回,那么在跳转之前需要在当前方法的基本信息压入栈中保存再跳转。
 
注意:jvm只是定义了线程的逻辑模型和原语,具体各家的物理实现不一
 

4、JVM常见调优

a)新生代设置合适

设置太小,minor GC频繁,而且可能导致老生代增加过快,产生full gc

设置太大,JVM基于悲观的策略,可能在minor GC的时候,判断old区剩余空间小,直接将新生代数据升级到老生代,触发full gc

b)合理设置Survivor space空间

设置过小,触发更多的minor gc

设置过大,对应的Eden区过小,minor gc可能触发更多的对象进入老生代,从而触发full gc

c)合理设置新生代存活时间

增大存活周期设置,在minor gc中尽量的将对象回收,降低进入老生代,但是带来的是s0和s1区的较多的占用

 

5、线程与JNI


在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory、

      针对每个线程,jvm给它在堆上分配了一块“自留地”——TLAB。TLAB全称是Thread Local Allocation Buffer,处于堆内存的年轻区,也就是Eden这个区域里。每个线程在创建新的对象时,会首先尝试在自己的TLAB里进行分配,如果成功就返回,失败了再到共享的Eden区里去申请空间。在自己的TLAB区域创建对象失败一般有两个原因:一个是对象太大,第二个是自己的TLAB区剩余空间不够。TLAB中的申请分配不会涉及到锁操作,对应的为线程的Threadlocal变量。

      这里就涉及到TLAB区域大小的问题了。通常默认的TLAB区域大小是Eden区域的1%,当然也可以手工进行调整,对应的JVM参数是-XX:TLABWasteTargetPercent。  


JNI 调用的时候,完全是堆外内存,个人感觉应该是:运行代码内存+堆内存+jni内存<进程最大内存,


7、常见问题

a)TLAB与Threadloacl


A TLAB is a Thread Local Allocation Buffer. The normal way objects are allocated in HotSpot is within a TLAB. TLAB allocations can be done without synchronization with other threads, since the Allocation Buffer is Thread Local, synchronization is only needed when a new TLAB is fetched.
So, the ideal scenario is that as much as possible of the allocations are done in TLABs.
Some objects will be allocated outside TLABs, for example large objects. This is nothing to worry about as long as the percentage of allocations outside TLABs vs allocations in new TLABs is low.
The TLABs are dynamically resized during the execution for each thread individually. So, if a thread allocates very much, the new TLABs that it gets from the heap will increase in size. If you want you can try to set the flag -XX:MinTLABSize to set minimum TLAB size, for example -XX:MinTLABSize=4k
Answer provided by my colleague David Lindholm :)


b)java中thread线程的实现

关键词: hotspot thread implements heap


java中的内存与操作系统内存关系

http://stackoverflow.com/questions/16264118/how-jvm-stack-heap-and-threads-are-mapped-to-physical-memory-or-operation-syste


Is frame in JVM heap allocated or stack allocated?  java中的frame如何分配

JVM stack is an abstraction. It may be allocated anywhere or nowhere at all. E.g. if a method is inlined by JIT, it does not have a separate stack frame.
HotSpot JVM uses native thread stack as JVM stack. However there are JVM implementations (CLDC HI, for instance) that allocate JVM stacks in Java Heap. The benefit of this approach is to have a single memory management for everything including thread stacks. Such JVM may run on a platform without standard memory manager (like libc) or even without OS.
JVM Heap is also an abstraction. It is not more "shared" between JVM threads than native thread stacks. The heap may have thread-local areas as well. At the same time native threads stacks reside in virtual memory which is also shared among all threads of the process.

简要翻译:

java stack是个抽象,可以在任何地方分配,当前hotspot是使用本地线程栈作为JVM的stack,但是 CLDC的JVM的线程栈在堆里实现,好处是这种这种jvm可以不依赖于操作系统或者内存管理程序比如libc。类比,jvm的堆也是一个抽象。


c)hotspot的运行overview

http://openjdk.java.net/groups/hotspot/docs/RuntimeOverview.html#Thread%20Management|outline

整体写的不错,后续抽空翻译下。


8、参考文档

http://yanan0628.iteye.com/blog/2281031

http://lhc1986.iteye.com/blog/1421832

http://blog.csdn.net/u011080472/article/details/51337422

http://blog.csdn.net/zxp_cpinfo/article/details/53521569

http://sesame.iteye.com/blog/622670?page=2#comments

http://ayufox.iteye.com/blog/723896 jni相关


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小小她爹

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

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

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

打赏作者

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

抵扣说明:

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

余额充值