002_JVM内存结构及调优学习

1. 常遇到关于内存溢出的错误
        java.lang包下
        StackOverflowError 很少
        OutOfMemoryError: heap space(堆空间) 比较常见
        OutOfMemoryError: PermGen space 经常出现

2. Java虚拟机结构和属性
        
        内存区域: 保存java类和对象的物理区域
        
        堆: Java的内存区域叫做堆(heap)
        
        堆被分成3个区域:
            新域(young generation)、旧域(tenured generation)、永久域(perm generation)
            标记为virtual的部分被保留下来,必要时才分配出去。
            
            新域: 有Eden和两个救助空间survivor组成,新对象存放在Eden中
            
            旧域: 对象在两个救助空间survivor之间移动,当它们足够"老",能够被移入到保存生存期较长对象的旧域
            
            永久域: 在虚拟机的整个生存期都生存的对象
            
        常用虚拟机配置选项属性
            
            -Xmx    Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定;

-Xms    Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值;

-Xmn    Java Heap Young区大小,不熟悉最好保留默认值;

-Xss    每个线程的Stack大小,不熟悉最好保留默认值;
            
            具体实施查看 remark001_几招搞定JVM内存设置.txt

3. JVM垃圾回收机制,2种回收方法,7种垃圾收集器
        
        2种回收方法
            引用计数: 当应用程序引用某一对象的时候,JVM增加引用数,当引用超出范围时,JVM减少引用数,
                            当某对象的引用数为0时,便可以进行垃圾回收机制。(早期JVM的技术)
                
            对象引用遍历(对象引用树) => 目前大多数JVM技术
                    对象引用遍历树,是将对象引用关系构建成一棵树,从一组根对象开始,沿着整个对象树上的每条链接,
                        递归确定可到达(reachable)的对象。如果某对象别的对象(至少一个)引用,则将它作为垃圾收集起来。
                    在对象遍历阶段,GC必须记住哪些对象可以到大,以便删除不可到达的对象,这称为标记(marking)对象。
                    
        7种垃圾收集器
            标记-清除收集器(Serial收集器): 对遍历对象图进行遍历,并标记可到达的对象,然后扫描对象以寻找未标记对象并释放内存。
                该收集器一般使用单线程工作并停止其它操作。
                (你妈妈在打扫房间,会叫你出去等一会)
                
            标记-清除-压缩收集器:
                与Serial收集器有相同的标记阶段。在第二阶段,把标记对象复制到堆栈的新域中以便压缩堆栈。
                这种收集器也会停止其它操作。
                
            复制收集器: 它将堆栈分为2个域,称为半空间,它每次仅使用一个半空间。
                GC运行时,JVM生成的新对象放在一个半空间中,将可到达对象复制到另一个半空间中,从而压缩堆栈。
                这种方法适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。
                
            增量收集器: 把堆栈分为多个域,每次仅从一个域收集垃圾。这会造成较小的应用程序中断。
            
            分代收集器: 把堆栈分成两个或多个域,用以存放不同寿命的对象。JVM生成的新对象一般放在其中的某个域中。
                过一段时间,继续存在的对象将获得使用期并转入更长寿命的域中。
                分代收集器对不同域使用不同的算法以优化性能。
            
            并发收集器: 同时发生,与应用程序同时运行。该收集器在某一时刻一般不得不停止其它操作以完成特定任务,
                但是因为其它应用程序可进行后台操作,所以中断其它处理的实际时间大大降低。
            
            并行收集器: 使用某种传统算法,并使用多线程并行执行它们的工作。在多CPU机器上使用多线程技术可以显著提高Java应用程序的可扩展性。
            
            解释两个名词:并发和并行。
                这两个名词都是并发编程中的概念,在谈论垃圾收集器的上下文语境中,他们可以解释为:
                    并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
                    并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),
                        用户程序继续运行,而垃圾收集程序运行于另一个CPU上。
                    
4. JVM内存区域配置: 堆区域、新域与旧域、永久区域(非堆内存)、新域子空间
        
        Sun的JVM使用的是分代收集器,它把堆分成3个主要域: 新域与旧域、永久区域(也叫非堆内存分配).
            JVM生成的所有新对象放在新域、一旦对象经历了一定数量的垃圾收集循环后,便获得使用期进入旧域。
            在永久域中JVM则存储类和方法对象。
        
        Java虚拟机的配置选项有专门用于对这些域进行配置的属性
            
            配置堆区域
                堆实质上就是新域+旧域的和,它代表这2个区域的内存大小。
                设置堆的初始大小和最大大小内存 128MB
                    java -Xms128m (其中s为start )
                    java -Xmx128m (其中x为max )
                
                通常可以将初始化大小设置为最大大小,这样可以避免程序动态增加堆的大小。
                
            配置新域和旧域
                
                设置新域大小64MB
                    java -Xms256m -Xmx256m -Xmn64m  (Xmn 其中n为new)
                    
                设置新域的初始值和最大值 64MB
                    (-XX:NewSize 设置新域初始值 )
                    (-XX:MaxNewsize 设置新域最大值 )
                    java -Xms256m -Xmx256m -XX:NewSize 64m -XX:MaxNewsize=64m
                
                设置了新域的大小,旧域大小即为堆的大小减去新域的大小,不需要对旧域进行设置,JVM也没有提供对旧域设置属性。
                
            配置永久域(非堆内存)
                
                永久域默认大小为4MB,运行程序时,JVM会调整永久域大小以满足需要。
                为了避免调整,可使用-XX:PermSize设置初始值,使用-XX:MaxPermSize设置最大值
                    java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m
                    
            配置新域子空间
                
                默认状态,JVM在新域使用复制收集器,对旧域使用标记-清除-压缩收集器。
                在新域
            
        JVM内存区域配置的实战案例: remark002_eclipse内存溢出崩溃_服务器JVM崩溃.txt    
    
5. JVM性能调优
    
        调优配置参考
                
            JVM的堆大小决定了JVM花费在收集垃圾上的时间和频度。
            
            应用中建立和释放对象的速度决定了垃圾收集的频度。
            
            编程中,注意使用对象的缓存而不是建立对象。
            
            对生存时间越长,需要收集时间也越长,收集也会变慢。
            
            一次完全的垃圾收集应该不超过3-5秒。
            
            如果系统花费很多时间收集垃圾,应该减少堆大小。
            
            一般来说,你使用物理内存的80%为堆大小。
            
            对于1GB内存,单CPU的机器来说,如下的一组参考配置
            
            -Xms800m -Xmx800m  // 堆初始值和堆最大值一样
            -Xmn200m           // 新域的内存
            -XX:PermSize=128m   // 永久域初始值
            -XX:MaxPermSize=128m // 永久域最大值
            -XX:NewSize=200m   // 新域的初始值
            -XX:MaxNewSize=200m // 新域最大值
            -XX:NewRatio=3        // 设置该值后可不设置NewSize
            -XX:SurvivorRatio=4 // 设置救助区域大小
            -XX:userParNewGC   // 可用来设置并行收集
            -XX:ParallelGCThreads   // 可用来增加并行度
            -XX:UseParallelGC  // 设置后可以使用并行清除收集器
            -XX:UseAdaptiveSizePolicy // 上面一个联合使用效果更好,利用它可以自动优化新域大小和救助空间比值
            
        我们经常遇到java.lang.OutOfMemoryError. Java heap space的错误
            
            根源是JVM虚拟机默认Heap大小是64MB,可通过设置最小值和最大值来解决
                
                (1) windows中更改系统环境变量
                    加上 JAVA_OPTS=-Xm800m -Xmx800m
                
                (2) tomcat的话,可以在\bin\catalina.bat或catalina.sh加上
                    set JAVA_OPTS=-Xm800m -Xmx800m
        
        JVM调优实战
            
            heap内存设置
            
                进入JAVA_HOME/demo/jfc/SwingSet2目录
                    java -jar -Xmn4m -Xms16m -Xmx16m SwingSet2.jar
                        出现如下错误: Exception in thread "Image Fetcher 1" java.lang.OutOfMemoryError: Java heap space
                    
                    除了异常信息,会发现程序的响应速度变慢。
                    说明Heap size偏小,GC占用了更多时间,应该分配到的执行时间较少。
                    
                    设置成如下,则安然无恙:
                        
                        java -jar -Xmn4m -Xms16m -Xmx32m SwingSet2.jar
                        
                    Heap最大不要超过可用物理内存的80%,一般要将-Xms和-Xmx选项设置为相同,
                    而-Xmn为1/4的-Xmx(heap最大值)

时间: 2024-08-27 11:44:57

002_JVM内存结构及调优学习的相关文章

Android内存分析和调优(上)

Android内存分析和调优(上) Android内存分析工具(四):adb命令

Linux内存监控与调优

首先,内存在被使用是被分为区域的 32位系统:zone_DMA ·zone_NORMAL (正常内存区域 16M) ·zone_RESRVED(用于高地址内存空间 896M) ·zone_HIGHMEM(高地址内存空间 ) 64位系统: ·zone_DMA(16G) ·zone_DMA32(4G) ·zone_normal(大于4G) 内存大页 : HugePage:大页面,在rhel 6 x64位系统上不但支持大页面而且支持使用透明大页 THP:透明大页,简单来讲就是对匿名内存的使用,不需要用

java内存泄露和调优

内存泄漏及解决方法1.系统崩溃前的一些现象:每次垃圾回收的时间越来越长,由之前的10ms延长到50ms左右,FullGC的时间也有之前的0.5s延长到4.5sFullGC的次数越来越多,最频繁时隔不到1分钟就进行一次FullGC年老代的内存越来越大并且每次FullGC后年老代没有内存被释放之后系统会无法响应新的请求,逐渐到达OutOfMemoryError的临界值. 2.生成堆的dump文件通过JMX的MBean生成当前的Heap信息,大小为一个3G(整个堆的大小)的hprof文件,如果没有启动

java 内存 垃圾回收调优

要了解Java垃圾收集机制,先理解JVM内存模式是非常重要的.今天我们将会了解JVM内存的各个部分.如何监控以及垃圾收集调优. Java(JVM)内存模型 正如你从上面的图片看到的,JVM内存被分成多个独立的部分.广泛地说,JVM堆内存被分为两部分——年轻代(Young Generation)和老年代(Old Generation). 年轻代 年轻代是所有新对象产生的地方.当年轻代内存空间被用完时,就会触发垃圾回收.这个垃圾回收叫做Minor GC.年轻代被分为3个部分——Enden区和两个Su

LAMP 系统性能调优:第1 部分: 基础环境调优-学习笔记

LAMP 最初是指Linux .Apache.MySQL 和PHP(或Perl). LAMP 环境调优 对任何系统进行调优的第一步都是了解它的工作原理.按照最简单的形式,基于LAMP 的应用程序是用PHP 这样的脚本语言编写的,它们作为Linux 主机上运行的Apache Web 服务器的一部分运行. PHP 应用程序通过请求的URL.所有表单数据和已捕获的任意会话信息从客户机获得信息,从而确定应该执行什么操作.如有必要,服务器会从MySQL 数据库(也在Linux 上运行)获得信息,将这些信息

【转】oracle内存分配和调优总结

转自 http://blog.itpub.net/12272958/viewspace-696834/ 一直都想总结一下oracle内存调整方面的知识,最近正好优化一个数据库内存参数,查找一些资料并且google很多下.现在记录下来,做下备份.  一.概述:        oracle 的内存可以按照共享和私有的角度分为系统全局区和进程全局区,也就是 SGA和 PGA(process global area or private global area).对于 SGA 区域内的内存来说,是共享的

JVM调优学习

1. 调优的原则: 合理编写代码 合理利用硬件资源 合理地进行条用 2. JVM调优的宗旨: 降低FULL GC的执行频次,减小GC的执行时间. 3. 添加常用的参数: -XX:+HeapDumpOnOutOfMemoryError 默认关闭 在发生内存溢出异常时是否生成堆转储快照, -Xloggc:D:/gc.log 打印GC的日志到文件 若为jdk1.8的编译器,设置垃圾回收器为G1 -XX:+UseG1GC -Xmn2g 设置年轻代的大小2G  经验值 1/4-1/3 , Age =15的

free vmstat查看内存及系统调优【转】

内存查看 查看内存是否存在瓶颈,使用top指令看比较麻烦,而free命令更为直观: [/home/weber#]free total used free shared buffers cached Mem: 501820 452028 49792 37064 5056 136732 -/+ buffers/cache: 310240 191580 Swap: 0 0 0 [/home/weber#]top top - 17:52:17 up 42 days, 7:10, 1 user, load

SQL调优学习之——sqlserver分页从低效到高效

背景 以前都是使用mysql和oracle,对sqlserver的使用不多.最近因项目原因,要读取其他项目的数据库,取出某个门的开关历史记录,而对方使用的是sqlserver,所以研究起了sqlserver的分页,经过几次实践,慢慢的从低效的分页写到了高效的分页. 表结构 history表 历史记录ID:id(唯一引索) 操作时间:time 开门或关门:flag 由谁操作:user_Id 属于哪个设备:device_id 下面我们先介绍四种分页的方法,以[一种低效]——[两种较高效]——[一种高