1、堆与栈java
一、堆是全部对象共享的,存储对象信息;算法
每个线程都有一个独立的线程栈,栈存储的是与当前线程相关的信息,包括局部变量、程序运行状态、方法返回值等。服务器
二、堆中存储的是对象,栈中存储的是基本类型和堆中对象的引用。多线程
三、栈的大小配置 -Xss并发
四、在运行栈中,基本类型和引用的处理是同样的,都是传值。spa
五、能够把一个对象看做为一棵树,对象的属性若是仍是对象,则仍是一棵树(非叶子节点),而基本类型则是叶子节点。操作系统
2、Java对象的大小线程
一、一个空的Object对象:对象
Object obj = new Object();递归
其所占的空间为: 8+4 =12 bytes 。其中8 bytes 是Java堆中对象的所需空间,4 bytes是栈中保存引用的所需空间
二、如下类
class NewObject
{
int count;
boolean flag;
Object obj;
}
其的对象 NewObject newObj = new NewObject();
newObj 所占空间 8 + 4 +1 + 4 = 17 bytes.
其中8 bytes 为 newObj 空对象大小,4 bytes为 int 大小,1 byte为 boolean 大小, 4 bytes为 obj引用大小。
又由于Java对象内存分配以8的整数倍来分,故而对象的大小为 24 bytes。
三、基本类型包装类的大小至少是16bytes。
3、强引用、软引用、弱引用
强引用:回收时候严格判断
软引用:内存紧张则回收,富余则不回收
弱引用:每次GC一定回收,生命周期只存在于一个垃圾回收周期。
4、GC 基本策略
一、引用计算:没法处理循环引用
二、标记-清除:从root节点开始标记全部引用对象,遍历堆,清除未标记对象。缺点是须要暂停整个应用,产生内存碎片。
三、复制:将内存分为两块,每次只使用其中一块。回收时候复制到另外一块。
四、标记整理:结合 “标记-清除” 和 “复制”, 不过不是复制到另外一块内存,而是将对象放紧凑。
5、GC 分区策略
一、增量收集:实时垃圾回收。
二、分代收集:把对象分为年轻代、年老代、持久代,对于不一样生命周期对象采用不一样算法。
6、GC 线程策略
一、串行收集:单线程处理,没法使用多处理器的优点。须要暂停整个运行环境。
优势:简单,效率高。
缺点:只适合小型应用,数据量比较小。
配置:-XX:+UseSerialGC
二、并行收集:多线程处理,速度快,效率高。须要暂停整个运行环境。
优势:吞吐量大,适用于数值计算、后台处理。
缺点:响应时间长。
配置:XX:+UseParallelGC -XX:+UseParallelOldGC -XX:ParallelGCThreads=<N> -XX:MaxGCPauseMillis=<N> -XX:GCTimeRatio=<N>
三、并发收集:GC的同时不须要暂停整个运行环境。
优势:响应时间快,适用于Web服务器等。
缺点:吞吐量没那么大。
配置:-XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=<N>
7、分代回收
一、年轻代(Yong):一个Eden区,两个Survivor区。Eden满,放入一个Survivor。Survivor放入另外一个Survivor。另外一个Survivor满,放入年老代。
二、年老代(Tenured):年轻代经历N次GC后,对象放到年老区。放的是生命周期较长的数据。
三、持久代(Permanent):Java 类的 Class 信息,与GC关系不大。
Minor GC:只要Eden满即触发,速度很快。
Full GC:整个堆回收,速度慢。在年老代或者持久代满的时候调用。
8、典型配置
java -Xmx3550m -Xms3550m -Xmn2g –Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0 XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-Xmx3550m: 最大可用内存
-Xms3550m:初始内存。此值能够设置与-Xmx相同,以免每次垃圾回收完成后JVM从新分配内存。
-Xmn2g:年轻代大小
-Xss128k:每一个线程的栈大小
-XX:NewRatio=4: 年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)
-XX:SurvivorRatio=4:年轻代中Eden区与Survivor区的大小比值
-XX:MaxPermSize=16m: 持久代大小
-XX:MaxTenuringThreshold=0: 垃圾最大年龄。若是设置为0的话,则年轻代对象不通过Survivor区,直接进入年老代
-XX:+UseParallelGC:选择并行收集器
-XX:ParallelGCThreads=20: 并行收集器的线程数
-XX:+UseParallelOldGC: 年老代垃圾收集方式为并行收集
-XX:MaxGCPauseMillis=100:每次年轻代垃圾回收的最长时间
-XX:+UseAdaptiveSizePolicy:自动选择年轻代区大小和相应的Survivor区比例
-XX:+UseConcMarkSweepGC:设置年老代为并发收集
-XX:+UseParNewGC: 设置年轻代为并行收集
-XX:CMSFullGCsBeforeCompaction=5:运行多少次GC之后对内存空间进行压缩、整理。
-XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩
9、调优总结
一、吞吐量优先:
年轻代大、并行垃圾收集、年老代小。
尽量回收掉大部分短时间对象,减小中期的对象,而年老代尽存放长期存活对象。
二、响应时间优先:
年轻代大、并发垃圾回收、年老代适中。
年老代使用并发收集器,因此其大小须要当心设置,通常要考虑并发会话率和会话持续时间等一些参数。若是堆设置小了,能够会形成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;若是堆大了,则须要较长的收集时间。
10、年老代碎片问题:
解决:
一、-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
二、-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的状况下,这里设置多少次Full GC后,对年老代进行压缩
11、常见JVM 异常
一、java.lang.OutOfMemoryError: Java heap space
缘由:典型的内存泄露,全部堆空间都被没法回收的垃圾对象占满。
解决:找到泄露点,通常是集合对象引用。
二、java.lang.OutOfMemoryError: PermGen space
缘由:持久代占满,没法为新的class分配存储空间而引起的异常。主要缘由是大量动态反射生成的类不断被加载。不一样的classloader 即使使用了相同的类,可是都会对其进行加载,至关于有一个class会被N个classloader加载N次。
解决:-XX:MaxPermSize=16m
三、java.lang.StackOverflowError
缘由:递归没有返回,或者循环调用。
解决:修正代码
四、Fatal: Stack size too small
缘由:线程空间大小被限制
解决:增大线程栈,-Xss2m。也多是代码内存泄露。
五、java.lang.OutOfMemoryError: unable to create new native thread
缘由:操做系统没有足够资源产生这个线程
解决:配置系统,如ulimit。减少线程栈大小,-Xss。