精华内容
下载资源
问答
  • JVM内存结构Java内存模型别再傻傻不清了

    万次阅读 多人点赞 2020-03-04 20:53:30
    JVM内存结构Java内存模型都是面试的热点问题,名字看感觉都差不多,网上有些博客也都把这个概念混着用,实际上他们之间差别还是挺大的。 通俗点说,JVM内存结构是与JVM的内部存储结构相关,而Java内存模型是与多...

    JVM内存结构和Java内存模型都是面试的热点问题,名字看感觉都差不多,网上有些博客也都把这两个概念混着用,实际上他们之间差别还是挺大的。
    通俗点说,JVM内存结构是与JVM的内部存储结构相关,而Java内存模型是与多线程编程相关,本文针对这两个总是被混用的概念展开讲解。

    JVM内存结构

    JVM构成

    说到JVM内存结构,就不会只是说内存结构的5个分区,而是会延展到整个JVM相关的问题,所以先了解下JVM的构成。

    在这里插入图片描述

    • Java源代码编译成Java Class文件后通过类加载器ClassLoader加载到JVM中
      • 类存放在方法区
      • 类创建的对象存放在
      • 堆中对象的调用方法时会使用到虚拟机栈,本地方法栈,程序计数器
      • 方法执行时每行代码由解释器逐行执行
      • 热点代码由JIT编译器即时编译
      • 垃圾回收机制回收堆中资源
      • 和操作系统打交道需要调用本地方法接口

    JVM内存结构

    程序计数器

    在这里插入图片描述
    (通过移位寄存器实现)

    • 程序计数器是线程私有的,每个线程单独持有一个程序计数器
    • 程序计数器不会内存溢出

    虚拟机栈

    • 栈:线程运行需要的内存空间

    • 栈帧:每一个方法运行需要的内存(包括参数,局部变量,返回地址等信息)

    • 每个线程只有一 个活动栈帧(栈顶的栈帧),对应着正在执行的代码
      在这里插入图片描述

    • 常见问题解析

      • 垃圾回收是否涉及栈内存:不涉及,垃圾回收只涉及堆内存

      • 栈内存分配越大越好吗:内存一定时,栈内存越大,线程数就越少,所以不应该过大

      • 方法内的局部变量是否是线程安全的:

        • 普通局部变量是安全的
        • 静态的局部变量是不安全的
        • 对象类型的局部变量被返回了是不安全的
        • 基本数据类型局部变量被返回时安全的
        • 参数传入对象类型变量是不安全的
        • 参数传入基本数据类型变量时安全的
      • 栈内存溢出(StackOverflowError)

        • 栈帧过多

          • 如递归调用没有正确设置结束条件
        • 栈帧过大

          • json数据转换 对象嵌套对象 (用户类有部门类属性,部门类由用户类属性)
        • 线程运行诊断

          • CPU占用过高(定位问题)

            • ‘top’命令获取进程编号,查找占用高的进程
            • ‘ps H -eo pid,tid,%cpu | grep 进程号’ 命令获取线程的进程id,线程id,cpu占用
            • 将查看到的占用高的线程的线程号转化成16进制的数 :如6626->19E2
            • ‘ jstack 进程id ’获取进程栈信息, 查找‘nid=0X19E2’的线程
            • 问题线程的最开始‘#数字’表示出现问题的行数,回到代码查看
          • 程序运行很长时间没有结果(死锁问题)

            • ‘ jstack 进程id ’获取进程栈信息
            • 查看最后20行左右有无‘Fount one Java-level deadlock’
            • 查看下面的死锁的详细信息描述和问题定位
            • 回到代码中定位代码进行解决

    本地方法栈

    • 本地方法栈为虚拟机使用到的 Native 方法服务
    • Native 方法是 Java 通过 JNI 直接调用本地 C/C++ 库,可以认为是 Native 方法相当于 C/C++ 暴露给 Java 的一个接口
    • 如notify,hashcode,wait等都是native方法

    • 通过new关键字创建的对象都会使用堆内存

    • 堆是线程共享的

    • 堆中有垃圾回收机制

    • 堆内存溢出(OutOfMemoryError)

      • 死循环创建对象
    • 堆内存诊断

      • 命令行方式

        • ‘jps’获取运行进程号
        • ‘jmap -heap 进程号’查看当前时刻的堆内存信息
      • jconsole

        • 命令行输入jconsole打开可视化的界面连接上进程
        • 可视化的检测连续的堆内存信息
      • jvisualvm

        • 命令行输入jvisualvm打开可视化界面选择进程
        • 可视化的查看堆内存信息

    方法区

    • 方法区只是一种概念上的规范,具体的实现各种虚拟机和不同版本不相同
      • HotSpot1.6 使用永久代作为方法区的实现
      • HotSpot1.8使用本地内存的元空间作为方法区的实现(但StringTable还是放在堆中)
        在这里插入图片描述
    • 常见问题
      • StringTable特性

        • 常量池中的字符串仅是字符,第一次使用时才变为对象

        • 利用串池机制,避免重复创建字符串

        • 字符串常量拼接原理是StringBuilder(1.8)

        • 字符串常量拼接原理是编译器优化

        • StringTable在1.6中存放在永久代,在1.8中存放在堆空间

        • intern方法主动将串池中没有的字符串对象放入串池

          • 1.8中:尝试放入串池,如果有就不放入,只返回一个引用;如果没有就放入串池,同时返回常量池中对象引用

          • 1.6中:尝试放入串池,如果有就不放入,只返回一个引用;如果没有就复制一个放进去(本身不放入),同时返回常量池中的对象引用

          • 字符串常量池分析(1.8环境)

            String s1 = "a";
            String s2 = "b";
            String s3 = "a"+"b";
            String s4 = s1+s2;
            String s5 = "ab";
            String s6 = s4.intern();
            
            
            System.out.println(s3==s4);// s3在常量池中,s4在堆上(intern尝试s4放入常量池,因为ab存在了就拒绝放入返回ab引用给s6,s4还是堆上的)
            System.out.println(s3==s5);// s3在常量池中,s4也在常量池中(字符串编译期优化)
            System.out.println(s3==s6);// s3在常量池中,s6是s4的intern返回常量池中ab的引用,所以也在常量池中
            
            
            String x2 = new String("c")+new String("d");
            String x1 = "cd";
            x2.intern();
            
            System.out.println(x1==x2);//x2调用intern尝试放入常量池,但常量池中已经有cd了,所以只是返回一个cd的引用,而x2还是堆上的引用
            
      • JVM调优三大参数(如: java -Xms128m -Xmx128m -Xss256k -jar xxxx.jar)

        • -Xss:规定了每个线程虚拟机栈的大小(影响并发线程数大小)
        • -Xms:堆大小的初始值(超过初始值会扩容到最大值)
        • -Xmx:堆大小的最大值(通常初始值和最大值一样,因为扩容会导致内存抖动,影响程序运行稳定性)
      • JVM内存结构中堆和栈的区别

        • 管理方式:栈自动释放,堆需要GC
        • 空间大小:栈比堆小
        • 碎片:栈产生的碎片远少于堆
        • 分配方式:栈支持静态分配和动态分配,堆只支持动态分配
        • 效率:栈的效率比堆高

    GC垃圾回收机制

    1. 垃圾判别方法

    引用计数算法
    • 判断对象的引用数量来决定对象是否可以被回收

    • 每个对象实例都有一个引用计数器,被引用则+1,完成引用则-1

    • 优点:执行效率高,程序执行受影响小

    • 缺点:无法检测出循环引用的情况,导致内存泄露

    可达性分析算法
    • Java虚拟机中的垃圾回收器采用可达性分析来探索所有存活对象

    • 扫描堆中的对象,看是否能沿着GC Root对象为起点的引用链找到该对象,找不到则可以回收

    • 哪些对象可以作为GC Root

    • 通过System Class Loader或者Boot Class Loader加载的class对象,通过自定义类加载器加载的class不一定是GC Root

      • 虚拟机栈中的引用的对象

      • 本地方法栈中JNI(natice方法)的引用的对象

      • 方法区中的常量引用的对象

      • 方法区中的类静态属性引用的对象

      • 处于激活状态的线程

      • 正在被用于同步的各种锁对象

      • GC保留的对象,比如系统类加载器等。

    2. 垃圾回收算法

    标记清除法
    • 标记没有被GC Root引用的对象
    • 清除被标记位置的内存
    • 优点:处理速度快
    • 缺点:造成空间不连续,产生内存碎片
      在这里插入图片描述
    标记整理法
    • 标记没有被GC Root引用的对象
    • 整理被引用的对象
    • 优点:空间连续,没有内存碎片
    • 缺点:整理导致效率较低

    在这里插入图片描述

    复制算法
    • 分配同等大小的内存空间
    • 标记被GC Root引用的对象
    • 将引用的对象连续的复制到新的内存空间
    • 清除原来的内存空间
    • 交换FROM空间和TO空间
    • 优点:空间连续,没有内存碎片
    • 缺点:占用双倍的内存空间
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

    3. 分代垃圾回收机制

    • 分代垃圾回收流程
      在这里插入图片描述

      • 对象首先分配在伊甸园区域
      • 新生代空间不足时,触发Minor GC,伊甸园和from存活的对象使用【复制算法】复制到to中,存活的对象年龄加一,并且交换from区和to区
      • Minor GC会引发Stop the world(STW)现象,暂停其他用户的线程。垃圾回收结束后,用户线程才恢复运行
      • 当对象寿命超过阈值时,会晋升至老年代,最大寿命是15(4位二进制)
      • 当老年代空间不足,会先尝试触发Minor GC,如果之后空间仍不足,会触发Full GC(STW时间更长,老年代可能使用标签清除或标记整理算法)
      • 当存放大对象新生代放不下而老年代可以放下,大文件会直接晋升到老年代
      • 当存放大对象新生代和老年代都放不下时,抛出OOM异常
    • 默认堆内存分配
      在这里插入图片描述

      • 新生代占1/3,老年代占2/3
      • -XX:NewRatio:老年代和年轻代内存大小的比例
      • 新生代中按8 1 1进行分配,两个幸存区大小需要保持一致
      • -XX:SurvivorRatio: Eden和Survivor的比值,默认是8(8:1)
    • GC相关VM参数
      在这里插入图片描述

    4. 垃圾回收器

    • 安全点(SafePoint)

      • 分析过程中对象引用关系不会发生改变的点

      • 产生安全点的地方:

        • 方法调用
        • 循环跳转
        • 异常跳转
      • 安全点的数量应该设置适中

    • 串行(SerialGC)

      • 单线程的垃圾回收器
      • 堆内存较小,CPU核数少,适合个人电脑
      • SerialGC收集器 (-XX:+UseSerialGC 复制算法) Client模式下默认的年轻代收集器
      • SerialGC Old收集器 (-XX:+UseSerialOldGC 标记-整理算法)Client模式下默认的老年代收集器
        在这里插入图片描述
    • 吞吐量优先(ParallelGC)

      • 多线程的垃圾回收器
      • 堆内存较大,多核CPU,适合服务器
      • 尽可能让单位时间内STW暂停时间最短(吞吐量=运行代码时间/(运行代码时间+垃圾回收时间))
      • 并行的执行
      • ParallelGC收集器(-XX:+UseParallelGC 复制算法) Server模式下默认的年轻代垃圾回收器
      • ParallelGC Old收集器(-XX:+UseParallelOldGC 复制算法)

      在这里插入图片描述

    • 响应时间优先(CMS -XX:+UseConcMarkSweepGC 标记清除算法)

      • 多线程的垃圾回收器

      • 堆内存较大,多核CPU,Server模式下默认的老年代垃圾回收器

      • 尽可能让单次STW暂停时间最短

      • 部分时期内可以并发执行

      • 执行流程

        • 初始标记:stop-the-world
        • 并发标记:并发追溯标记,程序不会停顿
        • 并发预清理:查找执行并发标记阶段从年轻代晋升到老年代的对象
        • 重新标记:暂停虚拟机,扫描CMS堆中的剩余对象
        • 并发清理:清理垃圾对象,程序不会停顿
        • 并发重置:重置CMS收集器的数据结构

    在这里插入图片描述

    • G1(-XX:+UseG1GC 复制+标记清除算法)

      • G1l垃圾回收器简介
      • 定义:Garbage First (2017 jdk9 默认)
      • 特点
        • 并发和并行
        • 分代收集
        • 空间整合
        • 可预测的停顿
      • 使用场景
        • 同时注重吞吐量和低延迟,默认暂停目标是200ms
        • 超大堆内存,会将整个堆划分为多个大小相等的Region(新生代和老年代不再物理隔离了)
        • 整体上是标记整理算法,两个区域之间是复制算法
    • 垃圾回收阶段

      • 新生代垃圾收集

        • 会发生STW
      • 新生代垃圾收集+并发标记

        • 在Young GC时会进行GC Root的初始标记
        • 老年代占用堆内存空间比例达到阈值时,进行并发标记(不会STW)
      • 混合收集,对新生代,幸存区和老年代都进行收集

        • 最终标记,会STW
        • 拷贝存活,会STW
        • 三种阶段循环交替
          在这里插入图片描述
    • Full GC

      • SerialGC

        • 新生代内存不足发生的垃圾收集:minor GC
        • 老年代内存不足发生的垃圾收集:full GC
      • ParallelGC

        • 新生代内存不足发生的垃圾收集:minor GC
        • 老年代内存不足发生的垃圾收集:full GC
      • CMS

        • 新生代内存不足发生的垃圾收集:minor GC

        • 老年代内存不足

          • 并发收集成功:并发的垃圾收集
          • 并发收集失败:串行的full GC
      • G1

        • 新生代内存不足发生的垃圾收集:minor GC

        • 老年代内存不足,达到阈值时进入并发标记和混合收集阶段

          • 如果回收速度>新产生垃圾的速度 :并发垃圾收集
          • 如果回收速度<新产生垃圾的速度:串行的full GC

    5. 四种引用

    在这里插入图片描述

    • 强引用

      • 最常见的对象:通过new关键字创建,通过GC Root能找到的对象。
      • 当所有的GC Root都不通过【强引用】引用该对象时,对象才能被垃圾回收
    • 软引用

      • 仅有【软引用】引用该对象时,在垃圾回收后,内存仍不足时会再次发起垃圾回收,回收软引用对象

      • 可以配合引用队列来释放软引用自身

      • 创建一个软引用:SoftReference ref = new SoftReference<>(new Object());

      • 软引用被回收后,仍然还保留一个null,如将软引用加入集合,回收后遍历集合仍然还存在一个null

        • 解决:使用引用队列,软引用关联的对象被回收时,软引用自身会被加入到引用队列中,通过queue.poll()取得对象进行删除
        • 创建一个而引用队列:ReferenceQueue queue = new ReferenceQueue<>();
        • 创建加入了引用队列的软引用:SoftReference ref = new SoftReference<>(new Object(),queue);
    • 弱引用

      • 仅有【弱引用】引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象
      • 可以配合引用队列来释放弱引用自身
      • 创建一个弱引用:WeakReference ref = new WeakReference<>(new Object());
      • 引用队列使用同软引用
    • 虚引用

      • 必须配合引用队列使用,主要配合ByteBuffer使用,被引用对象回收时,会将【虚引用】入队,由Reference Hanler线程调用虚引用相关方法释放【直接内存】(unsafe类中方法)
    • 终结器引用

      • 无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用队列入队(引用对象暂未回收),再由Finalizer线程通过终结器引用找到被引用对象并调用他的finalize方法,第二次gc时回收被引用对象

    类加载

    类加载器的分类

    在这里插入图片描述

    类加载过程

    在这里插入图片描述

    • 加载

      • 通过ClassLoader加载Class文件字节码,生成Class对象
    • 链接

      • 校验:检查加载的的Class的正确性和安全性

      • 准备:为类变量分配存储空间并设置类变量初始值

      • 解析:JVM将常量池内的符号引用转换为直接引用

    • 初始化

      • 执行类变量赋值和静态代码块

    LoadClass和forName的区别

    • Class.ForName得到的class是已经初始化完成的
    • ClassLoader.loadClass得到的class是还没有链接的

    双亲委派机制

    在这里插入图片描述

    • 什么是双亲委派机制
      • 当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。
    • 为什么要使用双亲委派机制
      • 防止重复加载同一个.class文件,通过委托去向上级问,加载过了就不用加载了。
      • 保证核心.class文件不会被串改,即使篡改也不会加载,即使加载也不会是同一个对象,因为不同加载器加载同一个.class文件也不是同一个class对象,从而保证了class执行安全

    自定义类加载器

    • 需求场景

      • 想要加载非classpath的随意路径的类文件
      • 通过接口来使用实现,希望解耦合
    • 步骤

      • 继承Classloader父类
      • 遵循双亲委派机制,重写findClass方法(不能重写loadClass,重写了就不符合双亲委派了)
      • 读取类的字节码
      • 调用父类的defineClass方法加载类
      • 使用者调用类加载的loadClass方法
    • 案例演示

    创建自定义类加载器

    public class MyClassLoader extends ClassLoader {
        private String path;
        private String classLoaderName;
    
        public MyClassLoader(String path, String classLoaderName) {
            this.path = path;
            this.classLoaderName = classLoaderName;
        }
    
        //用于寻找类文件
        @Override
        public Class findClass(String name) {
            byte[] b = loadClassData(name);
            return defineClass(name, b, 0, b.length);
        }
    
    
        //用于加载类文件
        private byte[] loadClassData(String name) {
            name = path + name + ".class";
    
            try (InputStream in = new FileInputStream(new File(name));
                 ByteArrayOutputStream out = new ByteArrayOutputStream();) {
                int i = 0;
                while ((i = in.read()) != -1) {
                    out.write(i);
                }
                return out.toByteArray();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    调用自定义类加载器加载类

    public class MyClassLoaderChecker {
        public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
            MyClassLoader m = new MyClassLoader("C:\\Users\\73787\\Desktop\\","myClassLoader");
            Class<?> c = m.loadClass("Robot");
            System.out.println(c.getClassLoader());
            c.newInstance();
        }
    }
    

    反射机制

    反射的定义

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

    反射的常用场景

    第三方应用开发过程中,会需要某个类的某个成员变量、方法或是属性是私有的或者只对系统应用开放,就可以通过Java的反射机制来获取所需的私有成员或者方法

    反射相关的类

    在这里插入图片描述

    Class类:

    代表类的实体,在运行的Java应用程序中表示类和接口

    • 获得类的方法

    在这里插入图片描述

    • 获得类中属性的方法

    在这里插入图片描述

    • 获得类中方法的方法
      在这里插入图片描述
    • 获取类中构造器的方法
      在这里插入图片描述
    Filed类

    Filed代表类的成员变量(属性)

    在这里插入图片描述

    Method类

    在这里插入图片描述

    Constructor类

    在这里插入图片描述

    案例

    定义一个Robot类

    public class Robot {
        //私有属性
        private String name;
        //公有方法
        public void sayHi(String hello){
            System.out.println(hello+" "+name);
        }
        //私有方法
        private String thorwHello(String tag){
            return "hello "+tag;
        }
    }
    

    编写一个反射应用类,针对私有的属性和方法必须设置setAccessible(true)才能进行访问

    public class ReflectSample {
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
            //加载类
            Class<?> rc = Class.forName("leetcode.Robot");
            //获取类实例
            Robot r = (Robot)rc.newInstance();
            //打印类名
            System.out.println(rc.getName());
            
            //加载一个私有方法
            Method getHello = rc.getDeclaredMethod("thorwHello",String.class);
            getHello.setAccessible(true);
            Object bob = getHello.invoke(r, "bob");
            System.out.println(bob);
           
             //加载一个公有方法
            Method sayHi = rc.getMethod("sayHi",String.class);
            Object welcome = sayHi.invoke(r,"welcome");
           
             //加载一个私有属性
            Field name = rc.getDeclaredField("name");
            name.setAccessible(true);
            name.set(r,"tom");
            sayHi.invoke(r,"welcome");
        }
    }
    

    Java内存模型

    什么是Java内存模型(JMM)

    • 通俗来说,JMM是一套多线程读写共享数据时,对数据的可见性,有序性和原子性的规则

    为什么会有Java内存模型

    JVM实现不同会造成“翻译”的效果不同,不同CPU平台的机器指令有千差万别,无法保证同一份代码并发下的效果一致。所以需要一套统一的规范来约束JVM的翻译过程,保证并发效果一致性

    原子性

    • 什么是原子性
      • 原子性指一系列的操作,要么全部执行成功,要么全部不执行,不会出现执行一半的情况,是不可分的。
    • 原子性怎么实现
      • 使用synchronized或Lock加锁实现,保证任一时刻只有一个线程访问该代码块
      • 使用原子操作
    • Java中的原子操作有哪些
      • 除long和double之外的基本类型的赋值操作(64位值,当成两次32位的进行操作)
      • 所有引用reference的赋值操作
      • java.concurrent.Atomic.*包中所有类的原子操作
    • 创建对象的过程是否是原子操作(常应用于双重检查+volatile创建单例场景)
      • 创建对象实际上有3个步骤,并不是原子性的
        • 创建一个空对象
        • 调用构造方法
        • 创建好的实例赋值给引用

    可见性

    • 什么是可见性问题
      • 可见性指的是当一个线程修改了某个共享变量的值,其他线程是否能够马上得知这个修改的值。
    • 为什么会有可见性问题、
      • 对于单线程程序来说,可见性是不存在的,因为我们在任何一个操作中修改了某个变量的值,后续的操作中都能读取这个变量值,并且是修改过的新值。
      • 对于多线程程序而言。由于线程对共享变量的操作都是线程拷贝到各自的工作内存进行操作后才写回到主内存中的,这就可能存在一个线程A修改了共享变量x的值,还未写回主内存时,另外一个线程B又对主内存中同一个共享变量x进行操作,但此时A线程工作内存中共享变量x对线程B来说并不可见,这种工作内存与主内存同步延迟现象就造成了可见性问题
        在这里插入图片描述
    • 如何解决可见性问题
      • 解决方法1:加volatile关键字保证可见性。当一个共享变量被volatile修饰时,它会保证修改的值立即被其他的线程看到,即修改的值立即更新到主存中,当其他线程需要读取时,它会去内存中读取新值
      • 解决方法2:使用synchronized和Lock保证可见性。因为它们可以保证任一时刻只有一个线程能访问共享资源,并在其释放锁之前将修改的变量刷新到内存中
    • 案例
    /**
    * 〈可见性问题分析〉
    *
    * @author Chkl
    * @create 2020/3/4
    * @since 1.0.0
    */
    public class FieldVisibility {
        int a = 1;
        int b = 2;
    
        private void change() {
            a = 3;
            b = a;
        }
        private void print() {
            System.out.println("b=" + b + ";a=" + a);
        }
        public static void main(String[] args) {
            while (true) {
                FieldVisibility test = new FieldVisibility();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        test.change();
                    }
                }).start();
    
    
    
    
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        test.print();
                    }
                }).start();
            }
        }
    }
    

    循环创建两类线程,一个线程用于做值的交换,一个线程用于打印值

    比较直观的三种结果

    • 打印线程先执行:b = 2, a = 1
    • 交换线程先执行:b = 3, a = 3
    • 交换线程执行到一半就切出去打印了,只执行了a=3赋值操作:b = 2 , a =3

    实际上除了很容易想到的三种情况外还有一种特殊情况:b = 3 , a = 1

    • 这种情况就是可见性问题
    • a的值在线程1(执行交换线程)的本地缓存中进行了更新,但是并没有同步到共享缓存,而b的值成功的更新到了共享缓存,导致线程2(执行打印线程)从共享缓存中获取到的数据并不是实时的最新数据
      -在这里插入图片描述

    有序性(重排序)

    • 什么是重排序
      • 在线程内部的两行代码的实际执行顺序和代码在Java文件中的逻辑顺序不一致,代码指令并不是严格按照代码语句顺序执行的,他们的顺序被改变了,这就是重排序。
    • 重排序的意义
      • JVM能根据处理器特性(CPU多级缓存系统、多核处理器等)适当的对机器指令进行重排序,使机器指令能更符合CPU的执行特性,最大限度的发挥机器性能。
      • 案例
        计算:
        a = 3;
        b = 2;
        a = a + 1;
        重排序优化前的instructions
        
        load a
        set to 3
        store 3
        
        load b
        set to 2
        store b
        
        load a
        set to 4
        store a
        
        经过重排序处理后
        
        load a
        set to 3
        set to 4
        store a
        
        
        load b
        set to 2
        store b
        
        上述少了两个指令,优化了性能
        
    • 重排序的3种情况
      • 编译器优化( JVM,JIT编辑器等): 编译器在不改变单线程程序语义放入前提下,可以重新安排语句的执行顺序
      • 指令级并行的重排序:现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
      • 内存系统的重排序: 由于处理器使用缓存和读写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
        在这里插入图片描述

    volatile

    • 什么是volatile

      • volatile是一种同步机制,比synchronized或者Lock相关类更轻量级,因为使用volacile并不会发生上下文切换等开销很大的行为
      • volatile是无锁的,并且只能修饰单个属性
    • 什么时候适合用vilatile

      • 一个共享变量始终只被各个线程赋值,没有其他操作
      • 作为刷新的触发器,引用刷新之后使修改内容对其他线程可见(如CopyOnRightArrayList底层动态数组通过volatile修饰,保证修改完成后通过引用变化触发volatile刷新,使其他线程可见)
    • volatile的作用

      • 可见性保障:修改一个volatile修饰变量之后,会立即将修改同步到主内存,使用一个volatile修饰的变量之前,会立即从主内存中刷新数据。保证读取的数据都是最新的,之前的修改都是可见的。
      • 有序性保障(禁止指令重排序优化):有volatile修饰的变量,赋值后多了一个“内存屏障“( 指令重排序时不能把后面的指令重排序到内存屏障之前的位置)
    • volatile的性能

      • volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

    happens-before规则

    什么是happens-before规则:前一个操作的结果可以被后续的操作获取。

    • 程序的顺序性规则:在一个线程内一段代码的执行结果是有序的。虽然还会指令重排,但是随便它怎么排,结果是按照我们代码的顺序生成的不会变!
    • volatile规则: 就是如果一个线程先去写一个volatile变量,然后一个线程去读这个变量,那么这个写操作的结果一定对读的这个线程可见。
    • 传递性规则:happens-before原则具有传递性,即A happens-before B , B happens-before C,那么A happens-before C。
    • 管程锁定规则:无论是在单线程环境还是多线程环境,对于同一个锁来说,一个线程对这个锁解锁之后,另一个线程获取了这个锁都能看到前一个线程的操作结果!(管程是一种通用的同步原语,synchronized就是管程的实现)
    • 线程启动规则:在主线程A执行过程中,启动子线程B,那么线程A在启动子线程B之前对共享变量的修改结果对线程B可见。
    • 线程终止规则: 在主线程A执行过程中,子线程B终止,那么线程B在终止之前对共享变量的修改结果在线程A中可见。
    • 线程中断规则: 对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生,可以通过Thread.interrupted()检测到是否发生中断。
    • 对象终结规则:一个对象的初始化的完成,也就是构造函数执行的结束一定 happens-before它的finalize()方法。

    如果有用,点个赞再走吧

    展开全文
  • CPU对外设的寻址为什么两种,编址的实现到底是怎么样的一个概念? 独立统一这两种编址形式,在系统启动以后是不是已经由CPU同时设定好,然后再根据用户使用的指令,临时决定使用哪种编址来寻址?? ...
    CPU对外设的寻址为什么会分这两种,编址的实现到底是怎么样的一个概念? 

    独立和统一这两种编址形式,在系统启动以后是不是已经由CPU同时设定好,然后再根据用户使用的指令,临时决定使用哪种编址来寻址??

    刚看有朋友说独立编址情况,需外围芯片支持,端口地址存在外围芯片中,那么统一编址的情况下是指外设接口中的寄存器被当作内存来使用吗?我可以用MOV等指令对其任意操作??

    自学中,诸多不解,请各路侠客指教~


    统一编址是把内存的每个存储单元与外设一编址并不是外设占用内存存储单元;例1111H   这个地址可以提供16个地址,内存储单元占10个,其余6个可以做为外设的地址。
    独立编址就是外设与内存分开来,例:1111H     这16个地址全给内存,可用MOV等指令访问,外设另外有地址,CPU用专用的指令访问外设。
    2:这个是由CPU自动设置的,这俩种只可选其中一种,并不是人为的。

    3:并不是当作内存来使用,而是像访问内存一样来访问外设。

    cpu有一根线,叫io/mem,这一根线,就控制了输出的地址是io地址,还是mem的地址。
    当译码的时候,把这一根线加上就是了。
    当然,你如果想把一个器件(外围设备)的编址,编到内存里也可以,那时候就要用mov来访问了。
    那是一样的。
    把内存编到io地址空间,也可以用in   ,out   指令来访问。都是一个样子的。


    展开全文
  • 假设CPU要读取一个int型4字节大小的数据到寄存器中,分两种情况讨论: <!--[if !supportLists]-->1、<!--[endif]-->数据从0字节开始 <!--[if !supportLists]-->2、<!--[endif]-->数据从1字节开始   ...

    原文: http://blog.csdn.net/liupeng900605/article/details/7530010


    首先由一个程序引入话题:

     1 //环境:vc6 + windows sp2
     2 //程序1
     3 #include <iostream>
     4 
     5 using namespace std;
     6 
     7 struct st1 
     8 {
     9     char a ;
    10     int  b ;
    11     short c ;
    12 };
    13 
    14 struct st2
    15 {
    16     short c ;
    17     char  a ;
    18     int   b ;
    19 };
    20 
    21 int main()
    22 {
    23     cout<<"sizeof(st1) is "<<sizeof(st1)<<endl;
    24     cout<<"sizeof(st2) is "<<sizeof(st2)<<endl;
    25     return 0 ;
    26 }
    27 

    程序的输出结果为:

     sizeof(st1) is 12

            sizeof(st2) is 8

     

    问题出来了,这两个一样的结构体,为什么sizeof的时候大小不一样呢?

    本文的主要目的就是解释明白这一问题。

     

    内存对齐,正是因为内存对齐的影响,导致结果不同。

    对于大多数的程序员来说,内存对齐基本上是透明的,这是编译器该干的活,编译器为程序中的每个数据单元安排在合适的位置上,从而导致了相同的变量,不同声明顺序的结构体大小的不同。

     那么编译器为什么要进行内存对齐呢?程序1中结构体按常理来理解sizeof(st1)和sizeof(st2)结果都应该是7,4(int) + 2(short) + 1(char) = 7 。经过内存对齐后,结构体的空间反而增大了。

    在解释内存对齐的作用前,先来看下内存对齐的规则

    <!--[if !supportLists]-->1、  <!--[endif]-->数据成员各自对齐:对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数,这个数据成员的自身长度) 的倍数。

    <!--[if !supportLists]-->2、  <!--[endif]-->结构(或联合)本身也要进行对齐:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

    #pragma pack(n) 表示设置为n字节对齐。 VC6默认8字节对齐


    以程序1为例解释对齐的规则 :

    St1 :char占一个字节,起始偏移为0 ,int 占4个字节,min(#pragma pack()指定的数,这个数据成员的自身长度) = 4(VC6默认8字节对齐),所以int按4字节对齐,起始偏移必须为4的倍数,所以起始偏移为4,在char后编译器会添加3个字节的额外字节,不存放任意数据。short占2个字节,按2字节对齐,起始偏移为8,正好是2的倍数,无须添加额外字节。到此规则1的数据成员对齐结束,此时的内存状态为:

    oxxx|oooo|oo

    0123 4567 89 (地址)

    (x表示额外添加的字节)

    共占10个字节。还要继续进行结构本身的对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行,st1结构中最大数据成员长度为int,占4字节,而默认的#pragma pack 指定的值为8,所以结果本身按照4字节对齐,结构总大小必须为4的倍数,需添加2个额外字节使结构的总大小为12 。此时的内存状态为:

    oxxx|oooo|ooxx

    0123 4567 89ab  (地址)

    到此内存对齐结束。St1占用了12个字节而非7个字节。

     St2 的对齐方法和st1相同,读者可自己完成。

     

    内存对齐的主要作用是:

    <!--[if !supportLists]-->1、  <!--[endif]-->平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

    <!--[if !supportLists]-->2、  <!--[endif]-->性能原因:经过内存对齐后,CPU的内存访问速度大大提升。具体原因稍后解释。

     图一:


    这是普通程序员心目中的内存印象,由一个个的字节组成,而CPU并不是这么看待的。

     图二:


    CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity(粒度)本人把它翻译为“内存读取粒度” 。【原文::memory access granularity,computer's processor  accesses memory in two-, four-, eight- 16- or even 32-byte chunks,不同CPU 粒度可能不一样

     

    假设CPU要读取一个int型4字节大小的数据到寄存器中,分两种情况讨论:

    <!--[if !supportLists]-->1、<!--[endif]-->数据从0字节开始

    <!--[if !supportLists]-->2、<!--[endif]-->数据从1字节开始

     

    再次假设内存读取粒度为4。

     图三:

    当该数据是从0字节开始时,很CPU只需读取内存一次即可把这4字节的数据完全读取到寄存器中。

     当该数据是从1字节开始时,问题变的有些复杂,此时该int型数据不是位于内存读取边界上,这就是一类内存未对齐的数据。

     

    图四:

     

    此时CPU先访问一次内存,读取0—3字节的数据进寄存器,并再次读取4—5字节的数据进寄存器,接着把0字节和6,7,8字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器。对一个内存未对齐的数据进行了这么多额外的操作,大大降低了CPU性能。

     这还属于乐观情况了,上文提到内存对齐的作用之一为平台的移植原因,因为以上操作只有有部分CPU肯干,其他一部分CPU遇到未对齐边界就直接罢工了。


       原文地址:http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html


    补充:

    什么是对齐,以及为什么要对齐:

     现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。 对齐的实现 通常,我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择时候目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。 但是,正因为我们一般不需要关心这个问题,所以因为编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是struct数据结构的sizeof结果,出乎意料。为此,我们需要对对齐算法所了解。

      作用:指定结构体、联合以及类成员的packing alignment;   语法:#pragma pack( [show] | [push | pop] [, identifier], n )  说明:1,pack提供数据声明级别的控制,对定义不起作用;2,调用pack时不指定参数,n将被设成默认值;3,一旦改变数据类型的alignment,直接效果就是占用memory的减少,但是performance会下降;  语法具体分析:1,show:可选参数;显示当前packing aligment的字节数,以warning message的形式被显示;2,push:可选参数;将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈;3,pop:可选参数;从internal compiler stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing alignment数值;如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal compiler stack中的record都将被pop直到identifier被找到,然后pop出identitier,同时设置packing alignment数值为当前栈顶的record;如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略;4,identifier:可选参数;当同push一起使用时,赋予当前被压入栈中的record一个名称;当同pop一起使用时,从internal compiler stack中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作;5,n:可选参数;指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16
    展开全文
  • 内存溢出的几原因解决办法

    万次阅读 多人点赞 2018-03-19 16:48:32
    对于JVM的内存写过的文章已经有点多了,而且有点烂了,不过说那么多大多数在解决OOM的情况,于此,本文就只阐述这个内容,携带一些分析理解部分扩展内容,也就是JVM宕机中的一些问题,OK,下面说下OOM的常见情况...
    对于JVM的内存写过的文章已经有点多了,而且有点烂了,不过说那么多大多数在解决OOM的情况,于此,本文就只阐述这个内容,携带一些分析和理解和部分扩展内容,也就是JVM宕机中的一些问题,OK,下面说下OOM的常见情况:

    第一类内存溢出,也是大家认为最多,第一反应认为是的内存溢出,就是堆栈溢出:

    那什么样的情况就是堆栈溢出呢?当你看到下面的关键字的时候它就是堆栈溢出了:

    java.lang.OutOfMemoryError: ......java heap space.....

    也就是当你看到heap相关的时候就肯定是堆栈溢出了,此时如果代码没有问题的情况下,适当调整-Xmx和-Xms是可以避免的,不过一定是代码没有问题的前提,为什么会溢出呢,要么代码有问题,要么访问量太多并且每个访问的时间太长或者数据太多,导致数据释放不掉,因为垃圾回收器是要找到那些是垃圾才能回收,这里它不会认为这些东西是垃圾,自然不会去回收了;主意这个溢出之前,可能系统会提前先报错关键字为:

    java.lang.OutOfMemoryError:GC over head limit exceeded

    这种情况是当系统处于高频的GC状态,而且回收的效果依然不佳的情况,就会开始报这个错误,这种情况一般是产生了很多不可以被释放的对象,有可能是引用使用不当导致,或申请大对象导致,但是java heap space的内存溢出有可能提前不会报这个错误,也就是可能内存就直接不够导致,而不是高频GC.

    第二类内存溢出,PermGen的溢出,或者PermGen 满了的提示,你会看到这样的关键字:

    关键信息为:

    java.lang.OutOfMemoryError: PermGen space

    原因:系统的代码非常多或引用的第三方包非常多、或代码中使用了大量的常量、或通过intern注入常量、或者通过动态代码加载等方法,导致常量池的膨胀,虽然JDK 1.5以后可以通过设置对永久带进行回收,但是我们希望的是这个地方是不做GC的,它够用就行,所以一般情况下今年少做类似的操作,所以在面对这种情况常用的手段是:增加-XX:PermSize和-XX:MaxPermSize的大小。

    第三类内存溢出:在使用ByteBuffer中的allocateDirect()的时候会用到,很多javaNIO的框架中被封装为其他的方法

    溢出关键字:

    java.lang.OutOfMemoryError: Direct buffer memory
    如果你在直接或间接使用了ByteBuffer中的allocateDirect方法的时候,而不做clear的时候就会出现类似的问题,常规的引用程序IO输出存在一个内核态与用户态的转换过程,也就是对应直接内存与非直接内存,如果常规的应用程序你要将一个文件的内容输出到客户端需要通过OS的直接内存转换拷贝到程序的非直接内存(也就是heap中),然后再输出到直接内存由操作系统发送出去,而直接内存就是由OS和应用程序共同管理的,而非直接内存可以直接由应用程序自己控制的内存,jvm垃圾回收不会回收掉直接内存这部分的内存,所以要注意了哦。

    如果经常有类似的操作,可以考虑设置参数:-XX:MaxDirectMemorySize

    第四类内存溢出错误:

    溢出关键字:

    java.lang.StackOverflowError

    这个参数直接说明一个内容,就是-Xss太小了,我们申请很多局部调用的栈针等内容是存放在用户当前所持有的线程中的,线程在jdk 1.4以前默认是256K,1.5以后是1M,如果报这个错,只能说明-Xss设置得太小,当然有些厂商的JVM不是这个参数,本文仅仅针对Hotspot VM而已;不过在有必要的情况下可以对系统做一些优化,使得-Xss的值是可用的。

    第五类内存溢出错误:

    溢出关键字:

    java.lang.OutOfMemoryError: unable to create new native thread

    上面第四种溢出错误,已经说明了线程的内存空间,其实线程基本只占用heap以外的内存区域,也就是这个错误说明除了heap以外的区域,无法为线程分配一块内存区域了,这个要么是内存本身就不够,要么heap的空间设置得太大了,导致了剩余的内存已经不多了,而由于线程本身要占用内存,所以就不够用了,说明了原因,如何去修改,不用我多说,你懂的。

    第六类内存溢出:

    溢出关键字

    java.lang.OutOfMemoryError: request {} byte for {}out of swap

    这类错误一般是由于地址空间不够而导致。

    六大类常见溢出已经说明JVM中99%的溢出情况,要逃出这些溢出情况非常困难,除非一些很怪异的故障问题会发生,比如由于物理内存的硬件问题,导致了code cache的错误(在由byte code转换为native code的过程中出现,但是概率极低),这种情况内存 会被直接crash掉,类似还有swap的频繁交互在部分系统中会导致系统直接被crash掉,OS地址空间不够的话,系统根本无法启动,呵呵;JNI的滥用也会导致一些本地内存无法释放的问题,所以尽量避开JNI;socket连接数据打开过多的socket也会报类似:IOException: Too many open files等错误信息。

    JNI就不用多说了,尽量少用,除非你的代码太牛B了,我无话可说,呵呵,这种内存如果没有在被调用的语言内部将内存释放掉(如C语言),那么在进程结束前这些内存永远释放不掉,解决办法只有一个就是将进程kill掉。

    另外GC本身是需要内存空间的,因为在运算和中间数据转换过程中都需要有内存,所以你要保证GC的时候有足够的内存哦,如果没有的话GC的过程将会非常的缓慢。

    顺便这里就提及一些新的CMS GC的内容和策略(有点乱,每次写都很乱,但是能看多少看多少吧):

    首先我再写一次一前博客中的已经写过的内容,就是很多参数没啥建议值,建议值是自己在现场根据实际情况科学计算和测试得到的综合效果,建议值没有绝对好的,而且默认值很多也是有问题的,因为不同的版本和厂商都有很大的区别,默认值没有永久都是一样的,就像-Xss参数的变化一样,要看到你当前的java程序heap的大致情况可以这样看看(以下参数是随便设置的,并不是什么默认值):

    $sudo jmap -heap `pgrep java` 
    Attaching to process ID 4280, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 19.1-b02

    using thread-local object allocation.
    Parallel GC with 8 thread(s)

    Heap Configuration:
    MinHeapFreeRatio = 40
    MaxHeapFreeRatio = 70
    MaxHeapSize = 1073741824 (1024.0MB)
    NewSize = 134217728 (128.0MB)
    MaxNewSize = 134217728 (128.0MB)
    OldSize = 5439488 (5.1875MB)
    NewRatio = 2
    SurvivorRatio = 8
    PermSize = 134217728 (128.0MB)
    MaxPermSize = 268435456 (256.0MB)

    Heap Usage:
    PS Young Generation
    Eden Space:
    capacity = 85721088 (81.75MB)
    used = 22481312 (21.439849853515625MB)
    free = 63239776 (60.310150146484375MB)
    26.22611602876529% used
    From Space:
    capacity = 24051712 (22.9375MB)
    used = 478488 (0.45632171630859375MB)
    free = 23573224 (22.481178283691406MB)
    1.9894134770946867% used
    To Space:
    capacity = 24248320 (23.125MB)
    used = 0 (0.0MB)
    free = 24248320 (23.125MB)
    0.0% used
    PS Old Generation
    capacity = 939524096 (896.0MB)
    used = 16343864 (15.586723327636719MB)
    free = 923180232 (880.4132766723633MB)
    1.7395896571023124% used
    PS Perm Generation
    capacity = 134217728 (128.0MB)
    used = 48021344 (45.796722412109375MB)
    free = 86196384 (82.20327758789062MB)
    35.77868938446045% used

    付:sudo是需要拿到管理员权限,如果你的系统权限很大那么就不需要了,最后的grep java那个内容如果不对,可以直接通过jps或者ps命令将和java相关的进程号直接写进去,如:java -map 4280,这个参数其实完全可以通过jstat工具来替代,而且看到的效果更加好,这个参数在线上应用中,尽量少用(尤其是高并发的应用中),可能会触发JVM的bug,导致应用挂起;在jvm 1.6u14后可以编写任意一段程序,然后在运行程序的时候,增加参数为:-XX:+PrintFlagsFinal来输出当前JVM中运行时的参数值,或者通过jinfo来查看,jinfo是非常强大的工具,可以对部分参数进行动态修改,当然内存相关的东西是不能修改的,只能增加一些不是很相关的参数,有关JVM的工具使用,后续文章中如果有机会我们再来探讨,不是本文的重点;补充:关于参数的默认值对不同的JVM版本、不同的厂商、运行于不同的环境(一般和位数有关系)默认值会有区别。

    OK,再说下反复的一句,没有必要的话就不要乱设置参数,参数不是拿来玩的,默认的参数对于这门JDK都是有好处的,关键是否适合你的应用场景,一般来讲你常规的只需要设置以下几个参数就可以了:

    -server 表示为服务器端,会提供很多服务器端默认的配置,如并行回收,而服务器上一般这个参数都是默认的,所以都是可以省掉,与之对应的还有一个-client参数,一般在64位机器上,JVM是默认启动-server参数,也就是默认启动并行GC的,但是是ParallelGC而不是ParallelOldGC,两者算法不同(后面会简单说明下),而比较特殊的是windows 32位上默认是-client,这两个的区别不仅仅是默认的参数不一样,在jdk包下的jre包下一般会包含client和server包,下面分别对应启动的动态链接库,而真正看到的java、javac等相关命令指示一个启动导向,它只是根据命令找到对应的JVM并传入jvm中进行启动,也就是看到的java.exe这些文件并不是jvm;说了这么多,最终总结一下就是,-server和-client就是完全不同的两套VM,一个用于桌面应用,一个用于服务器的。

    -Xmx 为Heap区域的最大值

    -Xms 为Heap区域的初始值,线上环境需要与-Xmx设置为一致,否则capacity的值会来回飘动,飘得你心旷神怡,你懂的。

    -Xss(或-ss) 这个其实也是可以默认的,如果你真的觉得有设置的必要,你就改下吧,1.5以后是1M的默认大小(指一个线程的native空间),如果代码不多,可以设置小点来让系统可以接受更大的内存。注意,还有一个参数是-XX:ThreadStackSize,这两个参数在设置的过程中如果都设置是有冲突的,一般按照JVM常理来说,谁设置在后面,就以谁为主,但是最后发现如果是在1.6以上的版本,-Xss设置在后面的确都是以-Xss为主,但是要是-XX:ThreadStackSize设置在后面,主线程还是为-Xss为主,而其它线程以-XX:ThreadStackSize为主,主线程做了一个特殊判定处理;单独设置都是以本身为主,-Xss不设置也不会采用其默认值,除非两个都不设置会采用-Xss的默认值。另外这个参数针对于hotspot的vm,在IBM的jvm中,还有一个参数为-Xoss,主要原因是IBM在对栈的处理上有操作数栈和方法栈等各种不同的栈种类,而hotspot不管是什么栈都放在一个私有的线程内部的,不区分是什么栈,所以只需要设置一个参数,而IBM的J9不是这样的;有关栈上的细节,后续我们有机会专门写文章来说明。

    -XX:PermSize-XX:MaxPermSize两个包含了class的装载的位置,或者说是方法区(但不是本地方法区),在Hotspot默认情况下为64M,主意全世界的JVM只有hostpot的VM才有Perm的区域,或者说只有hotspot才有对用户可以设置的这块区域,其他的JVM都没有,其实并不是没有这块区域,而是这块区域没有让用户来设置,其实这块区域本身也不应该让用户来设置,我们也没有一个明确的说法这块空间必须要设置多大,都是拍脑袋设置一个数字,如果发布到线上看下如果用得比较多,就再多点,如果用的少,就减少点,而这块区域和性能关键没有多大关系,只要能装下就OK,并且时不时会因为Perm不够而导致Full GC,所以交给开发者来调节这个参数不知道是怎么想的;所以Oracle将在新一代JVM中将这个区域彻底删掉,也就是对用户透明,G1的如果真正稳定起来,以后JVM的启动参数将会非常简单,而且理论上管理再大的内存也是没有问题的,其实G1(garbage first,一种基于region的垃圾收集回收器)已经在hotspot中开始有所试用,不过目前效果不好,还不如CMS呢,所以只是试用,G1已经作为ORACLE对JVM研发的最高重点,CMS自现在最高版本后也不再有新功能(可以修改bug),该项目已经进行5年,尚未发布正式版,CMS是四五年前发布的正式版,但是是最近一两年才开始稳定,而G1的复杂性将会远远超越CMS,所以要真正使用上G1还有待考察,全世界目前只有IBM J9真正实现了G1论文中提到的思想(论文于05年左右发表),IBM已经将J9应用于websphere中,但是并不代表这是全世界最好的jvm,全世界最好的jvm是Azul(无停顿垃圾回收算法和一个零开销的诊断/监控工具),几乎可以说这个jvm是没有暂停的,在全世界很多顶尖级的公司使用,不过价格非常贵,不能直接使用,目前这个jvm的主导者在研究JRockit,而目前hotspot和JRockit都是Oracle的,所以他们可能会合并,所以我们应该对JVM的性能充满信心。

    也就是说你常用的情况下只需要设置4个参数就OK了,除非你的应用有些特殊,否则不要乱改,那么来看看一些其他情况的参数吧:

    先来看个不大常用的,就是大家都知道JVM新的对象应该说几乎百分百的在Eden里面,除非Eden真的装不下,我们不考虑这种变态的问题,因为线上环境Eden区域都是不小的,来降低GC的次数以及全局 GC的概率;而JVM习惯将内存按照较为连续的位置进行分配,这样使得有足够的内存可以被分配,减少碎片,那么对于内存最后一个位置必然就有大量的征用问题,JVM在高一点的版本里面提出了为每个线程分配一些私有的区域来做来解决这个问题,而1.5后的版本还可以动态管理这些区域,那么如何自己设置和查看这些区域呢,看下英文全称为:Thread Local Allocation Buffer,简称就是:TLAB,即内存本地的持有的buffer,设置参数有:

    -XX:+UseTLAB 启用这种机制的意思
    -XX:TLABSize=<size in kb> 设置大小,也就是本地线程中的私有区域大小(只有这个区域放不下才会到Eden中去申请)。
    -XX:+ResizeTLAB 是否启动动态修改

    这几个参数在多CPU下非常有用。

    -XX:+PrintTLAB 可以输出TLAB的内容。

    下面再闲扯些其它的参数:

    如果你需要对Yong区域进行并行回收应该如何修改呢?在jdk1.5以后可以使用参数:

    -XX:+UseParNewGC

    注意: 与它冲突的参数是:-XX:+UseParallelOldGC-XX:+UseSerialGC,如果需要用这个参数,又想让整个区域是并行回收的,那么就使用-XX:+UseConcMarkSweepGC参数来配合,其实这个参数在使用了CMS后,默认就会启动该参数,也就是这个参数在CMS GC下是无需设置的,后面会提及到这些参数。

    默认服务器上的对Full并行GC策略为(这个时候Yong空间回收的时候启动PSYong算法,也是并行回收的):

    -XX:+UseParallelGC

    另外,在jdk1.5后出现一个新的参数如下,这个对Yong的回收算法和上面一样,对Old区域会有所区别,上面对Old回收的过程中会做一个全局的Compact,也就是全局的压缩操作,而下面的算法是局部压缩,为什么要局部压缩呢?是因为JVM发现每次压缩后再逻辑上数据都在Old区域的左边位置,申请的时候从左向右申请,那么生命力越长的对象就一般是靠左的,所以它认为左边的对象就是生命力很强,而且较为密集的,所以它针对这种情况进行部分密集,但是这两种算法mark阶段都是会暂停的,而且存活的对象越多活着的越多;而ParallelOldGC会进行部分压缩算法(主意一点,最原始的copy算法是不需要经过mark阶段,因为只需要找到一个或活着的就只需要做拷贝就可以,而Yong区域借用了Copy算法,只是唯一的区别就是传统的copy算法是采用两个相同大小的内存来拷贝,浪费空间为50%,所以分代的目标就是想要实现很多优势所在,认为新生代85%以上的对象都应该是死掉的,所以S0和S1一般并不是很大),该算法为jdk 1.5以后对于绝大部分应用的最佳选择。

    -XX:+UseParallelOldGC

    -XX:ParallelGCThread=12:并行回收的线程数,最好根据实际情况而定,因为线程多往往存在征用调度和上下文切换的开销;而且也并非CPU越多线程数也可以设置越大,一般设置为12就再增加用处也不大,主要是算法本身内部的征用会导致其线程的极限就是这样。

    设置Yong区域大小:

    -Xmn Yong区域的初始值和最大值一样大

    -XX:NewSize-XX:MaxNewSize如果设置以为一样大就是和-Xmn,在JRockit中会动态变化这些参数,根据实际情况有可能会变化出两个Yong区域,或者没有Yong区域,有些时候会生出来一个半长命对象区域;这里除了这几个参数外,还有一个参数是NewRatio是设置Old/Yong的倍数的,这几个参数都是有冲突的,服务器端建议是设置-Xmn就可以了,如果几个参数全部都有设置,-Xmn和-XX:NewSize与-XX:MaxNewSize将是谁设置在后面,以谁的为准,而-XX:NewSize -XX:MaxNewSize与-XX:NewRatio时,那么参数设置的结果可能会以下这样的(jdk 1.4.1后):

    min(MaxNewSize,max(NewSize, heap/(NewRatio+1)))

    -XX:NewRatio为Old区域为Yong的多少倍,间接设置Yong的大小,1.6中如果使用此参数,则默认会在适当时候被动态调整,具体请看下面参数UseAdaptiveSizepollcy 的说明。

    三个参数不要同时设置,因为都是设置Yong的大小的。

    -XX:SurvivorRatio:该参数为Eden与两个求助空间之一的比例,注意Yong的大小等价于Eden + S0 + S1,S0和S1的大小是等价的,这个参数为Eden与其中一个S区域的大小比例,如参数为8,那么Eden就占用Yong的80%,而S0和S1分别占用10%。

    以前的老版本有一个参数为:-XX:InitialSurivivorRatio,如果不做任何设置,就会以这个参数为准,这个参数的默认值就是8,不过这个参数并不是Eden/Survivor的大小,而是Yong/Survivor,所以所以默认值8,代表每一个S区域的空间大小为Yong区域的12.5%而不是10%。另外顺便提及一下,每次大家看到GC日志的时候,GC日志中的每个区域的最大值,其中Yong的空间最大值,始终比设置的Yong空间的大小要小一点,大概是小12.5%左右,那是因为每次可用空间为Eden加上一个Survivor区域的大小,而不是整个Yong的大小,因为可用空间每次最多是这样大,两个Survivor区域始终有一块是空的,所以不会加上两个来计算。

    -XX:MaxTenuringThreshold=15:在正常情况下,新申请的对象在Yong区域发生多少次GC后就会被移动到Old(非正常就是S0或S1放不下或者不太可能出现的Eden都放不下的对象),这个参数一般不会超过16(因为计数器从0开始计数,所以设置为15的时候相当于生命周期为16)。

    要查看现在的这个值的具体情况,可以使用参数:-XX:+PrintTenuringDistribution

    通过上面的jmap应该可以看出我的机器上的MinHeapFreeRatio和MaxHeapFreeRatio分别为40个70,也就是大家经常说的在GC后剩余空间小于40%时capacity开始增大,而大于70%时减小,由于我们不希望让它移动,所以这两个参数几乎没有意义,如果你需要设置就设置参数为:

    -XX:MinHeapFreeRatio=40
    -XX:MaxHeapFreeRatio=70

    JDK 1.6后有一个动态调节板块的,当然如果你的每一个板块都是设置固定值,这个参数也没有用,不过如果是非固定的,建议还是不要动态调整,默认是开启的,建议将其关掉,参数为:

    -XX:+UseAdaptiveSizepollcy 建议使用-XX:-UseAdaptiveSizepollcy关掉,为什么当你的参数设置了NewRatio、Survivor、MaxTenuringThreshold这几个参数如果在启动了动态更新情况下,是无效的,当然如果你设置-Xmn是有效的,但是如果设置的比例的话,初始化可能会按照你的参数去运行,不过运行过程中会通过一定的算法动态修改,监控中你可能会发现这些参数会发生改变,甚至于S0和S1的大小不一样。

    如果启动了这个参数,又想要跟踪变化,那么就使用参数:-XX:+PrintAdaptiveSizePolicy

    上面已经提到,javaNIO中通过Direct内存来提高性能,这个区域的大小默认是64M,在适当的场景可以设置大一些。

    -XX:MaxDirectMemorySize

    一个不太常用的参数:

    -XX:+ScavengeBeforeFullGC 默认是开启状态,在full GC前先进行minor GC。

    对于java堆中如果要设置大页内存,可以通过设置参数:

    付:此参数必须在操作系统的内核支持的基础上,需要在OS级别做操作为:

    echo 1024 > /proc/sys/vm/nr_hugepages

    echo 2147483647 > /proc/sys/kernel/shmmax

    -XX:+UseLargePages

    -XX:LargePageSizeInBytes

    此时整个JVM都将在这块内存中,否则全部不在这块内存中。

    javaIO的临时目录设置

    -Djava.io.tmpdir

    jstack会去寻找/tmp/hsperfdata_admin下去寻找与进程号相同的文件,32位机器上是没有问题的,64为机器的是有BUG的,在jdk 1.6u23版本中已经修复了这个bug,如果你遇到这个问题,就需要升级JDK了。

    还记得上次说的平均晋升大小吗,在并行GC时,如果平均晋升大小大于old剩余空间,则发生full GC,那么当小于剩余空间时,也就是平均晋升小于剩余空间,但是剩余空间小于eden + 一个survivor的空间时,此时就依赖于参数:

    -XX:-HandlePromotionFailure

    启动该参数时,上述情况成立就发生minor gc(YGC),大于则发生full gc(major gc)。

    一般默认直接分配的对象如果大于Eden的一半就会直接晋升到old区域,但是也可以通过参数来指定:

    -XX:PretenureSizeThreshold=2m 我个人不建议使用这个参数

    也就是当申请对象大于这个值就会晋升到old区域。

    传说中GC时间的限制,一个是通过比例限制,一个是通过最大暂停时间限制,但是GC时间能限制么,呵呵,在增量中貌似可以限制,不过不能限制住GC总体的时间,所以这个参数也不是那么关键。

    -XX:GCTimeRatio=

    -XX:MaxGCPauseMillis

    -XX:GCTimeLimit

    要看到真正暂停的时间就一个是看GCDetail的日志,另一个是设置参数看:

    -XX:+PrintGCApplicationStoppedTime

    有些人,有些人就是喜欢在代码里面里头写System.gc(),耍酷,这个不是测试程序是线上业务,这样将会导致N多的问题,不多说了,你应该懂的,不懂的话看下书吧,而RMI是很不听话的一个鸟玩意,EJB的框架也是基于RMI写的,RMI为什么不听话呢,就是它自己在里面非要搞个System.gc(),哎,为了放置频繁的做,频繁的做,你就将这个命令的执行禁用掉吧,当然程序不用改,不然那些EJB都跑步起来了,呵呵:

    -XX:+DisableExplicitGC 默认是没有禁用掉,写成+就是禁用掉的了,但是有些时候在使用allocateDirect的时候,很多时候还真需要System.gc来强制回收这块资源。

    内存溢出时导出溢出的错误信息:
    -XX:+HeapDumpOnOutOfMemoryError

    -XX:HeapDumpPath=/home/xieyu/logs/ 这个参数指定导出时的路径,不然导出的路径就是虚拟机的目标位置,不好找了,默认的文件名是:java_pid<进程号>.hprof,这个文件可以类似使用jmap -dump:file=....,format=b <pid>来dump类似的内容,文件后缀都是hprof,然后下载mat工具进行分析即可(不过内存有多大dump文件就多大,而本地分析的时候内存也需要那么大,所以很多时候下载到本地都无法启动是很正常的),后续文章有机会我们来说明这些工具,另外jmap -dump参数也不要经常用,会导致应用挂起哦;另外此参数只会在第一次输出OOM的时候才会进行堆的dump操作(java heap的溢出是可以继续运行再运行的程序的,至于web应用是否服务要看应用服务器自身如何处理,而c heap区域的溢出就根本没有dump的机会,因为直接就宕机了,目前系统无法看到c heap的大小以及内部变化,要看大小只能间接通过看JVM进程的内存大小(top或类似参数),这个大小一般会大于heap+perm的大小,多余的部分基本就可以认为是c heap的大小了,而看内部变化呢只有google perftools可以达到这个目的),如果内存过大这个dump操作将会非常长,所以hotspot如果以后想管理大内存,这块必须有新的办法出来。

    最后,用dump出来的文件,通过mat分析出来的结果往往有些时候难以直接确定到底哪里有问题,可以看到的维度大概有:那个类使用的内存最多,以及每一个线程使用的内存,以及线程内部每一个调用的类和方法所使用的内存,但是很多时候无法判定到底是程序什么地方调用了这个类或者方法,因为这里只能看到最终消耗内存的类,但是不知道谁使用了它,一个办法是扫描代码,但是太笨重,而且如果是jar包中调用了就不好弄了,另一种方法是写agent,那么就需要相应的配合了,但是有一个非常好的工具就是btrace工具(jdk 1.7貌似还不支持),可以跟踪到某个类的某个方法被那些类中的方法调用过,那这个问题就好说了,只要知道开销内存的是哪一个类,就能知道谁调用过它,OK,关于btrace的不是本文重点,网上都有,后续文章有机会再探讨,
    原理:
    No performance impact during runtime(无性能影响)
    Dumping a –Xmx512m heap
    Create a 512MB .hprof file(512M内存就dump出512M的空间大小)
    JVM is “dead” during dumping(死掉时dump)
    Restarting JVM during this dump will cause unusable .hprof file(重启导致文件不可用)

    注明的NUMA架构,在JVM中开始支持,当然也需要CPU和OS的支持才可以,需要设置参数为:

    -XX:+UseNUMA 必须在并行GC的基础上才有的

    老年代无法分配区域的最大等待时间为(默认值为0,但是也不要去动它):

    -XX:GCExpandToAllocateDelayMillis

    让JVM中所有的set和get方法转换为本地代码:

    -XX:+UseFastAccessorMethods

    以时间戳输出Heap的利用率

    -XX:+PrintHeapUsageOverTime

    在64bit的OS上面(其实一般达不到57位左右),由于指针会放大为8个byte,所以会导致空间使用增加,当然,如果内存够大,就没有问题,但是如果升级到64bit系统后,只是想让内存达到4G或者8G,那么就完全可以通过很多指针压缩为4byte就OK了,所以在提供以下参数(本参数于jdk 1.6u23后使用,并自动开启,所以也不需要你设置,知道就OK):

    -XX:+UseCompressedOops 请注意:这个参数默认在64bit的环境下默认启动,但是如果JVM的内存达到32G后,这个参数就会默认为不启动,因为32G内存后,压缩就没有多大必要了,要管理那么大的内存指针也需要很大的宽度了。

    后台JIT编译优化启动

    -XX:+BackgroundCompilation

    如果你要输出GC的日志以及时间戳,相关的参数有:

    -XX:+PrintGCDetails 输出GC的日志详情,包含了时间戳

    -XX:+PrintGCTimeStamps 输出GC的时间戳信息,按照启动JVM后相对时间的每次GC的相对秒值(毫秒在小数点后面),也就是每次GC相对启动JVM启动了多少秒后发生了这次GC

    -XX:+PrintGCDateStamps输出GC的时间信息,会按照系统格式的日期输出每次GC的时间

    -XX:+PrintGCTaskTimeStamps输出任务的时间戳信息,这个细节上比较复杂,后续有文章来探讨。

    -XX:-TraceClassLoading 跟踪类的装载

    -XX:-TraceClassUnloading 跟踪类的卸载

    -XX:+PrintHeapAtGC 输出GC后各个堆板块的大小。

    将常量信息GC信息输出到日志文件:

    -Xloggc:/home/xieyu/logs/gc.log

    现在面对大内存比较流行是是CMS GC(最少1.5才支持),首先明白CMS的全称是什么,不是传统意义上的内容管理系统(Content Management System)哈,第一次我也没看懂,它的全称是:Concurrent Mark Sweep,三个单词分别代表并发、标记、清扫(主意这里没有compact操作,其实CMS GC的确没有compact操作),也就是在程序运行的同时进行标记和清扫工作,至于它的原理前面有提及过,只是有不同的厂商在上面做了一些特殊的优化,比如一些厂商在标记根节点的过程中,标记完当前的根,那么这个根下面的内容就不会被暂停恢复运行了,而移动过程中,通过读屏障来看这个内存是不是发生移动,如果在移动稍微停一下,移动过去后再使用,hotspot还没这么厉害,暂停时间还是挺长的,只是相对其他的GC策略在面对大内存来讲是不错的选择。

    下面看一些CMS的策略(并发GC总时间会比常规的并行GC长,因为它是在运行时去做GC,很多资源征用都会影响其GC的效率,而总体的暂停时间会短暂很多很多,其并行线程数默认为:(上面设置的并行线程数 + 3)/ 4

    付:CMS是目前Hotspot管理大内存最好的JVM,如果是常规的JVM,最佳选择为ParallelOldGC,如果必须要以响应时间为准,则选择CMS,不过CMS有两个隐藏的隐患:

    1、CMS GC虽然是并发且并行运行的GC,但是初始化的时候如果采用默认值92%JVM 1.5的白皮书上描述为68%其实是错误的,1.6是正确的),就很容易出现问题,因为CMS GC仅仅针对Old区域,Yong区域使用ParNew算法,也就是Old的CMS回收和Yong的回收可以同时进行,也就是回收过程中Yong有可能会晋升对象Old,并且业务也可以同时运行,所以92%基本开始启动CMS GC很有可能old的内存就不够用了,当内存不够用的时候,就启动Full GC,并且这个Full GC是串行的,所以如果弄的不好,CMS会比并行GC更加慢,为什么要启用串行是因为CMS GC、并行GC、串行GC的继承关系决定的,简单说就是它没办法去调用并行GC的代码,细节说后续有文章来细节说明),建议这个值设置为70%左右吧,不过具体时间还是自己决定。

    2、CMS GC另一个大的隐患,其实不看也差不多应该清楚,看名字就知道,就是不会做Compact操作,它最恶心的地方也在这里,所以上面才说一般的应用都不使用它,它只有内存垃圾非常多,多得无法分配晋升的空间的时候才会出现一次compact,但是这个是Full GC,也就是上面的串行,很恐怖的,所以内存不是很大的,不要考虑使用它,而且它的算法十分复杂。

    还有一些小的隐患是:和应用一起征用CPU(不过这个不是大问题,增加CPU即可)、整个运行过程中时间比并行GC长(这个也不是大问题,因为我们更加关心暂停时间而不是运行时间,因为暂停会影响非常多的业务)。

    启动CMS为全局GC方法(注意这个参数也不能上面的并行GC进行混淆,Yong默认是并行的,上面已经说过

    -XX:+UseConcMarkSweepGC

    在并发GC下启动增量模式,只能在CMS GC下这个参数才有效。

    -XX:+CMSIncrementalMode

    启动自动调节duty cycle,即在CMS GC中发生的时间比率设置,也就是说这段时间内最大允许发生多长时间的GC工作是可以调整的。

    -XX:+CMSIncrementalPacing

    在上面这个参数设定后可以分别设置以下两个参数(参数设置的比率,范围为0-100):

    -XX:CMSIncrementalDutyCycleMin=0
    -XX:CMSIncrementalDutyCycle=10

    增量GC上还有一个保护因子(CMSIncrementalSafetyFactor),不太常用;CMSIncrementalOffset提供增量GC连续时间比率的设置;CMSExpAvgFactor为增量并发的GC增加权重计算。

    -XX:CMSIncrementalSafetyFactor=
    -XX:CMSIncrementalOffset= 
    -XX:CMSExpAvgFactor=

    是否启动并行CMS GC(默认也是开启的)

    -XX:+CMSParallelRemarkEnabled

    要单独对CMS GC设置并行线程数就设置(默认也不需要设置):

    -XX:ParallelCMSThreads

    对PernGen进行垃圾回收:

    JDK 1.5在CMS GC基础上需要设置参数(也就是前提是CMS GC才有):

    -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

    1.6以后的版本无需设置:-XX:+CMSPermGenSweepingEnabled,注意,其实一直以来Full GC都会触发对Perm的回收过程,CMS GC需要有一些特殊照顾,虽然VM会对这块区域回收,但是Perm回收的条件几乎不太可能实现,首先需要这个类的classloader必须死掉,才可以将该classloader下所有的class干掉,也就是要么全部死掉,要么全部活着;另外,这个classloader下的class没有任何object在使用,这个也太苛刻了吧,因为常规的对象申请都是通过系统默认的,应用服务器也有自己默认的classloader,要让它死掉可能性不大,如果这都死掉了,系统也应该快挂了。

    CMS GC因为是在程序运行时进行GC,不会暂停,所以不能等到不够用的时候才去开启GC,官方说法是他们的默认值是68%,但是可惜的是文档写错了,经过很多测试和源码验证这个参数应该是在92%的时候被启动,虽然还有8%的空间,但是还是很可怜了,当CMS发现内存实在不够的时候又回到常规的并行GC,所以很多人在没有设置这个参数的时候发现CMS GC并没有神马优势嘛,和并行GC一个鸟样子甚至于更加慢,所以这个时候需要设置参数(这个参数在上面已经说过,启动CMS一定要设置这个参数):

    -XX:CMSInitiatingOccupancyFraction=70

    这样保证Old的内存在使用到70%的时候,就开始启动CMS了;如果你真的想看看默认值,那么就使用参数:-XX:+PrintCMSInitiationStatistics 这个变量只有JDK 1.6可以使用 1.5不可以,查看实际值-XX:+PrintCMSStatistics;另外,还可以设置参数-XX:CMSInitiatingPermOccupancyFraction来设置Perm空间达到多少时启动CMS GC,不过意义不大。

    JDK 1.6以后有些时候启动CMS GC是根据计算代价进行启动,也就是不一定按照你指定的参数来设置的,如果你不想让它按照所谓的成本来计算GC的话,那么你就使用一个参数:-XX:+UseCMSInitiatingOccupancyOnly,默认是false,它就只会按照你设置的比率来启动CMS GC了。如果你的程序中有System.gc以及设置了ExplicitGCInvokesConcurrent在jdk 1.6中,这种情况使用NIO是有可能产生问题的。

    启动CMS GC的compation操作,也就是发生多少次后做一次全局的compaction:

    -XX:+UseCMSCompactAtFullCollection

    -XX:CMSFullGCsBeforeCompaction:发生多少次CMS Full GC,这个参数最好不要设置,因为要做compaction的话,也就是真正的Full GC是串行的,非常慢,让它自己去决定什么时候需要做compaction。

    -XX:CMSMaxAbortablePrecleanTime=5000 设置preclean步骤的超时时间,单位为毫秒,preclean为cms gc其中一个步骤,关于cms gc步骤比较多,本文就不细节探讨了。

    并行GC在mark阶段,可能会同时发生minor GC,old区域也可能发生改变,于是并发GC会对发生了改变的内容进行remark操作,这个触发的条件是:

    -XX:CMSScheduleRemarkEdenSizeThreshold

    -XX:CMSScheduleRemarkEdenPenetration

    即Eden区域多大的时候开始触发,和eden使用量超过百分比多少的时候触发,前者默认是2M,后者默认是50%。

    但是如果长期不做remark导致old做不了,可以设置超时,这个超时默认是5秒,可以通过参数:

    -XX:CMSMaxAbortablePrecleanTime

    -XX:+ExplicitGCInvokesConcurrent 在显示发生GC的时候,允许进行并行GC。

    -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses 几乎和上面一样,只不过多一个对Perm区域的回收而已。

    补充:

    其实JVM还有很多的版本,很多的厂商,与其优化的原则,随便举两个例子hotspot在GC中做的一些优化(这里不说代码的编译时优化或运行时优化):

    Eden申请的空间对象由Old区域的某个对象的一个属性指向(也就是Old区域的这个空间不回收,Eden这块就没有必要考虑回收),所以Hotspot在CPU写上面,做了一个屏障,当发生赋值语句的时候(对内存来讲赋值就是一种写操作),如果发现是一个新的对象由Old指向Eden,那么就会将这个对象记录在一个卡片机里面,这个卡片机是有很多512字节的卡片组成,当在YGC过程中,就基本不会去移动或者管理这块对象(付:这种卡片机会在CMS GC的算法中使用,不过和这个卡片不是放在同一个地方的,也是CMS GC的关键,对于CMS GC的算法细节描述,后续文章我们单独说明)。

    Old区域对于一些比较大的对象,JVM就不会去管理个对象,也就是compact过程中不会去移动这块对象的区域等等吧。

    以上大部分参数为hotspot的自带关于性能的参数,参考版本为JDK 1.5和1.6的版本,很多为个人经验说明,不足以说明所有问题,如果有问题,欢迎探讨;另外,JDK的参数是不是就只有这些呢,肯定并不是,我知道的也不止这些,但是有些觉得没必要说出来的参数和一些数学运算的参数我就不想给出来了,比如像禁用掉GC的参数有神马意义,我们的服务器要是把这个禁用掉干个屁啊,呵呵,做测试还可以用这玩玩,让它不做GC直接溢出;还有一些什么计算因子啥的,还有很多复杂的数学运算规则,要是把这个配置明白了,就太那个了,而且一般情况下也没那个必要,JDK到现在的配置参数多达上500个以上,要知道完的话慢慢看吧,不过意义不大,而且要知道默认值最靠谱的是看源码而不是看文档,官方文档也只能保证绝大部是正确的,不能保证所有的是正确的。

    本文最后追加在jdk 1.6u 24后通过上面说明的-XX:+PrintFlagsFinal输出的参数以及默认值(还是那句话,在不同的平台上是不一样的),输出的参数如下,可以看看JVM的参数是相当的多,参数如此之多,你只需要掌握关键即可,参数还有很多有冲突的,不要纠结于每一个参数的细节:

    $java -XX:+PrintFlagsFinal

    uintx AdaptivePermSizeWeight = 20 {product}
    uintx AdaptiveSizeDecrementScaleFactor = 4 {product}
    uintx AdaptiveSizeMajorGCDecayTimeScale = 10 {product}
    uintx AdaptiveSizePausePolicy = 0 {product}
    uintx AdaptiveSizePolicyCollectionCostMargin = 50 {product}
    uintx AdaptiveSizePolicyInitializingSteps = 20 {product}
    uintx AdaptiveSizePolicyOutputInterval = 0 {product}
    uintx AdaptiveSizePolicyWeight = 10 {product}
    uintx AdaptiveSizeThroughPutPolicy = 0 {product}
    uintx AdaptiveTimeWeight = 25 {product}
    bool AdjustConcurrency = false {product}
    bool AggressiveOpts = false {product}
    intx AliasLevel = 3 {product}
    intx AllocatePrefetchDistance = -1 {product}
    intx AllocatePrefetchInstr = 0 {product}
    intx AllocatePrefetchLines = 1 {product}
    intx AllocatePrefetchStepSize = 16 {product}
    intx AllocatePrefetchStyle = 1 {product}
    bool AllowJNIEnvProxy = false {product}
    bool AllowParallelDefineClass = false {product}
    bool AllowUserSignalHandlers = false {product}
    bool AlwaysActAsServerClassMachine = false {product}
    bool AlwaysCompileLoopMethods = false {product}
    intx AlwaysInflate = 0 {product}
    bool AlwaysLockClassLoader = false {product}
    bool AlwaysPreTouch = false {product}
    bool AlwaysRestoreFPU = false {product}
    bool AlwaysTenure = false {product}
    bool AnonymousClasses = false {product}
    bool AssertOnSuspendWaitFailure = false {product}
    intx Atomics = 0 {product}
    uintx AutoGCSelectPauseMillis = 5000 {product}
    intx BCEATraceLevel = 0 {product}
    intx BackEdgeThreshold = 100000 {pd product}
    bool BackgroundCompilation = true {pd product}
    uintx BaseFootPrintEstimate = 268435456 {product}
    intx BiasedLockingBulkRebiasThreshold = 20 {product}
    intx BiasedLockingBulkRevokeThreshold = 40 {product}
    intx BiasedLockingDecayTime = 25000 {product}
    intx BiasedLockingStartupDelay = 4000 {product}
    bool BindGCTaskThreadsToCPUs = false {product}
    bool BlockOffsetArrayUseUnallocatedBlock = false {product}
    bool BytecodeVerificationLocal = false {product}
    bool BytecodeVerificationRemote = true {product}
    intx CICompilerCount = 1 {product}
    bool CICompilerCountPerCPU = false {product}
    bool CITime = false {product}
    bool CMSAbortSemantics = false {product}
    uintx CMSAbortablePrecleanMinWorkPerIteration = 100 {product}
    intx CMSAbortablePrecleanWaitMillis = 100 {product}
    uintx CMSBitMapYieldQuantum = 10485760 {product}
    uintx CMSBootstrapOccupancy = 50 {product}
    bool CMSClassUnloadingEnabled = false {product}
    uintx CMSClassUnloadingMaxInterval = 0 {product}
    bool CMSCleanOnEnter = true {product}
    bool CMSCompactWhenClearAllSoftRefs = true {product}
    uintx CMSConcMarkMultiple = 32 {product}
    bool CMSConcurrentMTEnabled = true {product}
    uintx CMSCoordinatorYieldSleepCount = 10 {product}
    bool CMSDumpAtPromotionFailure = false {product}
    uintx CMSExpAvgFactor = 50 {product}
    bool CMSExtrapolateSweep = false {product}
    uintx CMSFullGCsBeforeCompaction = 0 {product}
    uintx CMSIncrementalDutyCycle = 10 {product}
    uintx CMSIncrementalDutyCycleMin = 0 {product}
    bool CMSIncrementalMode = false {product}
    uintx CMSIncrementalOffset = 0 {product}
    bool CMSIncrementalPacing = true {product}
    uintx CMSIncrementalSafetyFactor = 10 {product}
    uintx CMSIndexedFreeListReplenish = 4 {product}
    intx CMSInitiatingOccupancyFraction = -1 {product}
    intx CMSInitiatingPermOccupancyFraction = -1 {product}
    intx CMSIsTooFullPercentage = 98 {product}
    double CMSLargeCoalSurplusPercent = {product}
    double CMSLargeSplitSurplusPercent = {product}
    bool CMSLoopWarn = false {product}
    uintx CMSMaxAbortablePrecleanLoops = 0 {product}
    intx CMSMaxAbortablePrecleanTime = 5000 {product}
    uintx CMSOldPLABMax = 1024 {product}
    uintx CMSOldPLABMin = 16 {product}
    uintx CMSOldPLABNumRefills = 4 {product}
    uintx CMSOldPLABReactivityCeiling = 10 {product}
    uintx CMSOldPLABReactivityFactor = 2 {product}
    bool CMSOldPLABResizeQuicker = false {product}
    uintx CMSOldPLABToleranceFactor = 4 {product}
    bool CMSPLABRecordAlways = true {product}
    uintx CMSParPromoteBlocksToClaim = 16 {product}
    bool CMSParallelRemarkEnabled = true {product}
    bool CMSParallelSurvivorRemarkEnabled = true {product}
    bool CMSPermGenPrecleaningEnabled = true {product}
    uintx CMSPrecleanDenominator = 3 {product}
    uintx CMSPrecleanIter = 3 {product}
    uintx CMSPrecleanNumerator = 2 {product}
    bool CMSPrecleanRefLists1 = true {product}
    bool CMSPrecleanRefLists2 = false {product}
    bool CMSPrecleanSurvivors1 = false {product}
    bool CMSPrecleanSurvivors2 = true {product}
    uintx CMSPrecleanThreshold = 1000 {product}
    bool CMSPrecleaningEnabled = true {product}
    bool CMSPrintChunksInDump = false {product}
    bool CMSPrintObjectsInDump = false {product}
    uintx CMSRemarkVerifyVariant = 1 {product}
    bool CMSReplenishIntermediate = true {product}
    uintx CMSRescanMultiple = 32 {product}
    uintx CMSRevisitStackSize = 1048576 {product}
    uintx CMSSamplingGrain = 16384 {product}
    bool CMSScavengeBeforeRemark = false {product}
    uintx CMSScheduleRemarkEdenPenetration = 50 {product}
    uintx CMSScheduleRemarkEdenSizeThreshold = 2097152 {product}
    uintx CMSScheduleRemarkSamplingRatio = 5 {product}
    double CMSSmallCoalSurplusPercent = {product}
    double CMSSmallSplitSurplusPercent = {product}
    bool CMSSplitIndexedFreeListBlocks = true {product}
    intx CMSTriggerPermRatio = 80 {product}
    intx CMSTriggerRatio = 80 {product}
    bool CMSUseOldDefaults = false {product}
    intx CMSWaitDuration = 2000 {product}
    uintx CMSWorkQueueDrainThreshold = 10 {product}
    bool CMSYield = true {product}
    uintx CMSYieldSleepCount = 0 {product}
    intx CMSYoungGenPerWorker = 16777216 {product}
    uintx CMS_FLSPadding = 1 {product}
    uintx CMS_FLSWeight = 75 {product}
    uintx CMS_SweepPadding = 1 {product}
    uintx CMS_SweepTimerThresholdMillis = 10 {product}
    uintx CMS_SweepWeight = 75 {product}
    bool CheckJNICalls = false {product}
    bool ClassUnloading = true {product}
    intx ClearFPUAtPark = 0 {product}
    bool ClipInlining = true {product}
    uintx CodeCacheExpansionSize = 32768 {pd product}
    uintx CodeCacheFlushingMinimumFreeSpace = 1536000 {product}
    uintx CodeCacheMinimumFreeSpace = 512000 {product}
    bool CollectGen0First = false {product}
    bool CompactFields = true {product}
    intx CompilationPolicyChoice = 0 {product}
    intx CompilationRepeat = 0 {C1 product}
    ccstrlist CompileCommand = {product}
    ccstr CompileCommandFile = {product}
    ccstrlist CompileOnly = {product}
    intx CompileThreshold = 1500 {pd product}
    bool CompilerThreadHintNoPreempt = true {product}
    intx CompilerThreadPriority = -1 {product}
    intx CompilerThreadStackSize = 0 {pd product}
    uintx ConcGCThreads = 0 {product}
    bool ConvertSleepToYield = true {pd product}
    bool ConvertYieldToSleep = false {product}
    bool DTraceAllocProbes = false {product}
    bool DTraceMethodProbes = false {product}
    bool DTraceMonitorProbes = false {product}
    uintx DefaultMaxRAMFraction = 4 {product}
    intx DefaultThreadPriority = -1 {product}
    intx DeferPollingPageLoopCount = -1 {product}
    intx DeferThrSuspendLoopCount = 4000 {product}
    bool DeoptimizeRandom = false {product}
    bool DisableAttachMechanism = false {product}
    bool DisableExplicitGC = false {product}
    bool DisplayVMOutputToStderr = false {product}
    bool DisplayVMOutputToStdout = false {product}
    bool DontCompileHugeMethods = true {product}
    bool DontYieldALot = false {pd product}
    bool DumpSharedSpaces = false {product}
    bool EagerXrunInit = false {product}
    intx EmitSync = 0 {product}
    uintx ErgoHeapSizeLimit = 0 {product}
    ccstr ErrorFile = {product}
    bool EstimateArgEscape = true {product}
    intx EventLogLength = 2000 {product}
    bool ExplicitGCInvokesConcurrent = false {product}
    bool ExplicitGCInvokesConcurrentAndUnloadsClasses = false {produ
    bool ExtendedDTraceProbes = false {product}
    bool FLSAlwaysCoalesceLarge = false {product}
    uintx FLSCoalescePolicy = 2 {product}
    double FLSLargestBlockCoalesceProximity = {product}
    bool FailOverToOldVerifier = true {product}
    bool FastTLABRefill = true {product}
    intx FenceInstruction = 0 {product}
    intx FieldsAllocationStyle = 1 {product}
    bool FilterSpuriousWakeups = true {product}
    bool ForceFullGCJVMTIEpilogues = false {product}
    bool ForceNUMA = false {product}
    bool ForceSharedSpaces = false {product}
    bool ForceTimeHighResolution = false {product}
    intx FreqInlineSize = 325 {pd product}
    intx G1ConcRefinementGreenZone = 0 {product}
    intx G1ConcRefinementRedZone = 0 {product}
    intx G1ConcRefinementServiceIntervalMillis = 300 {product}
    uintx G1ConcRefinementThreads = 0 {product}
    intx G1ConcRefinementThresholdStep = 0 {product}
    intx G1ConcRefinementYellowZone = 0 {product}
    intx G1ConfidencePercent = 50 {product}
    uintx G1HeapRegionSize = 0 {product}
    intx G1MarkRegionStackSize = 1048576 {product}
    intx G1RSetRegionEntries = 0 {product}
    uintx G1RSetScanBlockSize = 64 {product}
    intx G1RSetSparseRegionEntries = 0 {product}
    intx G1RSetUpdatingPauseTimePercent = 10 {product}
    intx G1ReservePercent = 10 {product}
    intx G1SATBBufferSize = 1024 {product}
    intx G1UpdateBufferSize = 256 {product}
    bool G1UseAdaptiveConcRefinement = true {product}
    bool G1UseFixedWindowMMUTracker = false {product}
    uintx GCDrainStackTargetSize = 64 {product}
    uintx GCHeapFreeLimit = 2 {product}
    bool GCLockerInvokesConcurrent = false {product}
    bool GCOverheadReporting = false {product}
    intx GCOverheadReportingPeriodMS = 100 {product}
    intx GCPauseIntervalMillis = 500 {product}
    uintx GCTaskTimeStampEntries = 200 {product}
    uintx GCTimeLimit = 98 {product}
    uintx GCTimeRatio = 99 {product}
    ccstr HPILibPath = {product}
    bool HandlePromotionFailure = true {product}
    uintx HeapBaseMinAddress = 2147483648 {pd product}
    bool HeapDumpAfterFullGC = false {manageable}
    bool HeapDumpBeforeFullGC = false {manageable}
    bool HeapDumpOnOutOfMemoryError = false {manageable}
    ccstr HeapDumpPath = {manageable}
    uintx HeapFirstMaximumCompactionCount = 3 {product}
    uintx HeapMaximumCompactionInterval = 20 {product}
    bool IgnoreUnrecognizedVMOptions = false {product}
    uintx InitialCodeCacheSize = 163840 {pd product}
    uintx InitialHeapSize := 16777216 {product}
    uintx InitialRAMFraction = 64 {product}
    uintx InitialSurvivorRatio = 8 {product}
    intx InitialTenuringThreshold = 7 {product}
    uintx InitiatingHeapOccupancyPercent = 45 {product}
    bool Inline = true {product}
    intx InlineSmallCode = 1000 {pd product}
    intx InterpreterProfilePercentage = 33 {product}
    bool JNIDetachReleasesMonitors = true {product}
    bool JavaMonitorsInStackTrace = true {product}
    intx JavaPriority10_To_OSPriority = -1 {product}
    intx JavaPriority1_To_OSPriority = -1 {product}
    intx JavaPriority2_To_OSPriority = -1 {product}
    intx JavaPriority3_To_OSPriority = -1 {product}
    intx JavaPriority4_To_OSPriority = -1 {product}
    intx JavaPriority5_To_OSPriority = -1 {product}
    intx JavaPriority6_To_OSPriority = -1 {product}
    intx JavaPriority7_To_OSPriority = -1 {product}
    intx JavaPriority8_To_OSPriority = -1 {product}
    intx JavaPriority9_To_OSPriority = -1 {product}
    bool LIRFillDelaySlots = false {C1 pd product}
    uintx LargePageHeapSizeThreshold = 134217728 {product}
    uintx LargePageSizeInBytes = 0 {product}
    bool LazyBootClassLoader = true {product}
    bool ManagementServer = false {product}
    uintx MarkStackSize = 32768 {product}
    uintx MarkStackSizeMax = 4194304 {product}
    intx MarkSweepAlwaysCompactCount = 4 {product}
    uintx MarkSweepDeadRatio = 5 {product}
    intx MaxBCEAEstimateLevel = 5 {product}
    intx MaxBCEAEstimateSize = 150 {product}
    intx MaxDirectMemorySize = -1 {product}
    bool MaxFDLimit = true {product}
    uintx MaxGCMinorPauseMillis = 4294967295 {product}
    uintx MaxGCPauseMillis = 4294967295 {product}
    uintx MaxHeapFreeRatio = 70 {product}
    uintx MaxHeapSize := 268435456 {product}
    intx MaxInlineLevel = 9 {product}
    intx MaxInlineSize = 35 {product}
    intx MaxJavaStackTraceDepth = 1024 {product}
    uintx MaxLiveObjectEvacuationRatio = 100 {product}
    uintx MaxNewSize = 4294967295 {product}
    uintx MaxPermHeapExpansion = 4194304 {product}
    uintx MaxPermSize = 67108864 {pd product}
    uint64_t MaxRAM = 1073741824 {pd product}
    uintx MaxRAMFraction = 4 {product}
    intx MaxRecursiveInlineLevel = 1 {product}
    intx MaxTenuringThreshold = 15 {product}
    intx MaxTrivialSize = 6 {product}
    bool MethodFlushing = true {product}
    intx MinCodeCacheFlushingInterval = 30 {product}
    uintx MinHeapDeltaBytes = 131072 {product}
    uintx MinHeapFreeRatio = 40 {product}
    intx MinInliningThreshold = 250 {product}
    uintx MinPermHeapExpansion = 262144 {product}
    uintx MinRAMFraction = 2 {product}
    uintx MinSurvivorRatio = 3 {product}
    uintx MinTLABSize = 2048 {product}
    intx MonitorBound = 0 {product}
    bool MonitorInUseLists = false {product}
    bool MustCallLoadClassInternal = false {product}
    intx NUMAChunkResizeWeight = 20 {product}
    intx NUMAPageScanRate = 256 {product}
    intx NUMASpaceResizeRate = 1073741824 {product}
    bool NUMAStats = false {product}
    intx NativeMonitorFlags = 0 {product}
    intx NativeMonitorSpinLimit = 20 {product}
    intx NativeMonitorTimeout = -1 {product}
    bool NeedsDeoptSuspend = false {pd product}
    bool NeverActAsServerClassMachine = true {pd product}
    bool NeverTenure = false {product}
    intx NewRatio = 2 {product}
    uintx NewSize = 1048576 {product}
    uintx NewSizeThreadIncrease = 4096 {pd product}
    intx NmethodSweepFraction = 4 {product}
    uintx OldPLABSize = 1024 {product}
    uintx OldPLABWeight = 50 {product}
    uintx OldSize = 4194304 {product}
    bool OmitStackTraceInFastThrow = true {product}
    ccstrlist OnError = {product}
    ccstrlist OnOutOfMemoryError = {product}
    intx OnStackReplacePercentage = 933 {pd product}
    uintx PLABWeight = 75 {product}
    bool PSChunkLargeArrays = true {product}
    intx ParGCArrayScanChunk = 50 {product}
    uintx ParGCDesiredObjsFromOverflowList = 20 {product}
    bool ParGCTrimOverflow = true {product}
    bool ParGCUseLocalOverflow = false {product}
    intx ParallelGCBufferWastePct = 10 {product}
    bool ParallelGCRetainPLAB = true {product}
    uintx ParallelGCThreads = 0 {product}
    bool ParallelGCVerbose = false {product}
    uintx ParallelOldDeadWoodLimiterMean = 50 {product}
    uintx ParallelOldDeadWoodLimiterStdDev = 80 {product}
    bool ParallelRefProcBalancingEnabled = true {product}
    bool ParallelRefProcEnabled = false {product}
    uintx PausePadding = 1 {product}
    intx PerBytecodeRecompilationCutoff = 200 {product}
    intx PerBytecodeTrapLimit = 4 {product}
    intx PerMethodRecompilationCutoff = 400 {product}
    intx PerMethodTrapLimit = 100 {product}
    bool PerfAllowAtExitRegistration = false {product}
    bool PerfBypassFileSystemCheck = false {product}
    intx PerfDataMemorySize = 32768 {product}
    intx PerfDataSamplingInterval = 50 {product}
    ccstr PerfDataSaveFile = {product}
    bool PerfDataSaveToFile = false {product}
    bool PerfDisableSharedMem = false {product}
    intx PerfMaxStringConstLength = 1024 {product}
    uintx PermGenPadding = 3 {product}
    uintx PermMarkSweepDeadRatio = 20 {product}
    uintx PermSize = 12582912 {pd product}
    bool PostSpinYield = true {product}
    intx PreBlockSpin = 10 {product}
    intx PreInflateSpin = 10 {pd product}
    bool PreSpinYield = false {product}
    bool PreferInterpreterNativeStubs = false {pd product}
    intx PrefetchCopyIntervalInBytes = -1 {product}
    intx PrefetchFieldsAhead = -1 {product}
    intx PrefetchScanIntervalInBytes = -1 {product}
    bool PreserveAllAnnotations = false {product}
    uintx PreserveMarkStackSize = 1024 {product}
    uintx PretenureSizeThreshold = 0 {product}
    bool PrintAdaptiveSizePolicy = false {product}
    bool PrintCMSInitiationStatistics = false {product}
    intx PrintCMSStatistics = 0 {product}
    bool PrintClassHistogram = false {manageable}
    bool PrintClassHistogramAfterFullGC = false {manageable}
    bool PrintClassHistogramBeforeFullGC = false {manageable}
    bool PrintCommandLineFlags = false {product}
    bool PrintCompilation = false {product}
    bool PrintConcurrentLocks = false {manageable}
    intx PrintFLSCensus = 0 {product}
    intx PrintFLSStatistics = 0 {product}
    bool PrintFlagsFinal := true {product}
    bool PrintFlagsInitial = false {product}
    bool PrintGC = false {manageable}
    bool PrintGCApplicationConcurrentTime = false {product}
    bool PrintGCApplicationStoppedTime = false {product}
    bool PrintGCDateStamps = false {manageable}
    bool PrintGCDetails = false {manageable}
    bool PrintGCTaskTimeStamps = false {product}
    bool PrintGCTimeStamps = false {manageable}
    bool PrintHeapAtGC = false {product rw}
    bool PrintHeapAtGCExtended = false {product rw}
    bool PrintHeapAtSIGBREAK = true {product}
    bool PrintJNIGCStalls = false {product}
    bool PrintJNIResolving = false {product}
    bool PrintOldPLAB = false {product}
    bool PrintPLAB = false {product}
    bool PrintParallelOldGCPhaseTimes = false {product}
    bool PrintPromotionFailure = false {product}
    bool PrintReferenceGC = false {product}
    bool PrintRevisitStats = false {product}
    bool PrintSafepointStatistics = false {product}
    intx PrintSafepointStatisticsCount = 300 {product}
    intx PrintSafepointStatisticsTimeout = -1 {product}
    bool PrintSharedSpaces = false {product}
    bool PrintTLAB = false {product}
    bool PrintTenuringDistribution = false {product}
    bool PrintVMOptions = false {product}
    bool PrintVMQWaitTime = false {product}
    uintx ProcessDistributionStride = 4 {product}
    bool ProfileInterpreter = false {pd product}
    bool ProfileIntervals = false {product}
    intx ProfileIntervalsTicks = 100 {product}
    intx ProfileMaturityPercentage = 20 {product}
    bool ProfileVM = false {product}
    bool ProfilerPrintByteCodeStatistics = false {product}
    bool ProfilerRecordPC = false {product}
    uintx PromotedPadding = 3 {product}
    intx QueuedAllocationWarningCount = 0 {product}
    bool RangeCheckElimination = true {product}
    intx ReadPrefetchInstr = 0 {product}
    intx ReadSpinIterations = 100 {product}
    bool ReduceSignalUsage = false {product}
    intx RefDiscoveryPolicy = 0 {product}
    bool ReflectionWrapResolutionErrors = true {product}
    bool RegisterFinalizersAtInit = true {product}
    bool RelaxAccessControlCheck = false {product}
    bool RequireSharedSpaces = false {product}
    uintx ReservedCodeCacheSize = 33554432 {pd product}
    bool ResizeOldPLAB = true {product}
    bool ResizePLAB = true {product}
    bool ResizeTLAB = true {pd product}
    bool RestoreMXCSROnJNICalls = false {product}
    bool RewriteBytecodes = false {pd product}
    bool RewriteFrequentPairs = false {pd product}
    intx SafepointPollOffset = 256 {C1 pd product}
    intx SafepointSpinBeforeYield = 2000 {product}
    bool SafepointTimeout = false {product}
    intx SafepointTimeoutDelay = 10000 {product}
    bool ScavengeBeforeFullGC = true {product}
    intx SelfDestructTimer = 0 {product}
    uintx SharedDummyBlockSize = 536870912 {product}
    uintx SharedMiscCodeSize = 4194304 {product}
    uintx SharedMiscDataSize = 4194304 {product}
    uintx SharedReadOnlySize = 10485760 {product}
    uintx SharedReadWriteSize = 12582912 {product}
    bool ShowMessageBoxOnError = false {product}
    intx SoftRefLRUPolicyMSPerMB = 1000 {product}
    bool SplitIfBlocks = true {product}
    intx StackRedPages = 1 {pd product}
    intx StackShadowPages = 3 {pd product}
    bool StackTraceInThrowable = true {product}
    intx StackYellowPages = 2 {pd product}
    bool StartAttachListener = false {product}
    intx StarvationMonitorInterval = 200 {product}
    bool StressLdcRewrite = false {product}
    bool StressTieredRuntime = false {product}
    bool SuppressFatalErrorMessage = false {product}
    uintx SurvivorPadding = 3 {product}
    intx SurvivorRatio = 8 {product}
    intx SuspendRetryCount = 50 {product}
    intx SuspendRetryDelay = 5 {product}
    intx SyncFlags = 0 {product}
    ccstr SyncKnobs = {product}
    intx SyncVerbose = 0 {product}
    uintx TLABAllocationWeight = 35 {product}
    uintx TLABRefillWasteFraction = 64 {product}
    uintx TLABSize = 0 {product}
    bool TLABStats = true {product}
    uintx TLABWasteIncrement = 4 {product}
    uintx TLABWasteTargetPercent = 1 {product}
    bool TaggedStackInterpreter = false {product}
    intx TargetPLABWastePct = 10 {product}
    intx TargetSurvivorRatio = 50 {product}
    uintx TenuredGenerationSizeIncrement = 20 {product}
    uintx TenuredGenerationSizeSupplement = 80 {product}
    uintx TenuredGenerationSizeSupplementDecay = 2 {product}
    intx ThreadPriorityPolicy = 0 {product}
    bool ThreadPriorityVerbose = false {product}
    uintx ThreadSafetyMargin = 52428800 {product}
    intx ThreadStackSize = 0 {pd product}
    uintx ThresholdTolerance = 10 {product}
    intx Tier1BytecodeLimit = 10 {product}
    bool Tier1OptimizeVirtualCallProfiling = true {C1 product}
    bool Tier1ProfileBranches = true {C1 product}
    bool Tier1ProfileCalls = true {C1 product}
    bool Tier1ProfileCheckcasts = true {C1 product}
    bool Tier1ProfileInlinedCalls = true {C1 product}
    bool Tier1ProfileVirtualCalls = true {C1 product}
    bool Tier1UpdateMethodData = false {product}
    intx Tier2BackEdgeThreshold = 100000 {pd product}
    intx Tier2CompileThreshold = 1500 {pd product}
    intx Tier3BackEdgeThreshold = 100000 {pd product}
    intx Tier3CompileThreshold = 2500 {pd product}
    intx Tier4BackEdgeThreshold = 100000 {pd product}
    intx Tier4CompileThreshold = 4500 {pd product}
    bool TieredCompilation = false {pd product}
    bool TimeLinearScan = false {C1 product}
    bool TraceBiasedLocking = false {product}
    bool TraceClassLoading = false {product rw}
    bool TraceClassLoadingPreorder = false {product}
    bool TraceClassResolution = false {product}
    bool TraceClassUnloading = false {product rw}
    bool TraceGen0Time = false {product}
    bool TraceGen1Time = false {product}
    ccstr TraceJVMTI = {product}
    bool TraceLoaderConstraints = false {product rw}
    bool TraceMonitorInflation = false {product}
    bool TraceParallelOldGCTasks = false {product}
    intx TraceRedefineClasses = 0 {product}
    bool TraceSafepointCleanupTime = false {product}
    bool TraceSuspendWaitFailures = false {product}
    intx TypeProfileMajorReceiverPercent = 90 {product}
    intx TypeProfileWidth = 2 {product}
    intx UnguardOnExecutionViolation = 0 {product}
    bool Use486InstrsOnly = false {product}
    bool UseAdaptiveGCBoundary = false {product}
    bool UseAdaptiveGenerationSizePolicyAtMajorCollection = true {p
    bool UseAdaptiveGenerationSizePolicyAtMinorCollection = true {p
    bool UseAdaptiveNUMAChunkSizing = true {product}
    bool UseAdaptiveSizeDecayMajorGCCost = true {product}
    bool UseAdaptiveSizePolicy = true {product}
    bool UseAdaptiveSizePolicyFootprintGoal = true {product}
    bool UseAdaptiveSizePolicyWithSystemGC = false {product}
    bool UseAddressNop = false {product}
    bool UseAltSigs = false {product}
    bool UseAutoGCSelectPolicy = false {product}
    bool UseBiasedLocking = true {product}
    bool UseBoundThreads = true {product}
    bool UseCMSBestFit = true {product}
    bool UseCMSCollectionPassing = true {product}
    bool UseCMSCompactAtFullCollection = true {product}
    bool UseCMSInitiatingOccupancyOnly = false {product}
    bool UseCodeCacheFlushing = false {product}
    bool UseCompiler = true {product}
    bool UseCompilerSafepoints = true {product}
    bool UseConcMarkSweepGC = false {product}
    bool UseCountLeadingZerosInstruction = false {product}
    bool UseCounterDecay = true {product}
    bool UseDepthFirstScavengeOrder = true {product}
    bool UseFastAccessorMethods = true {product}
    bool UseFastEmptyMethods = true {product}
    bool UseFastJNIAccessors = true {product}
    bool UseG1GC = false {product}
    bool UseGCOverheadLimit = true {product}
    bool UseGCTaskAffinity = false {product}
    bool UseHeavyMonitors = false {product}
    bool UseInlineCaches = true {product}
    bool UseInterpreter = true {product}
    bool UseLWPSynchronization = true {product}
    bool UseLargePages = false {pd product}
    bool UseLargePagesIndividualAllocation := false {pd product}
    bool UseLoopCounter = true {product}
    bool UseMaximumCompactionOnSystemGC = true {product}
    bool UseMembar = false {product}
    bool UseNUMA = false {product}
    bool UseNewFeature1 = false {C1 product}
    bool UseNewFeature2 = false {C1 product}
    bool UseNewFeature3 = false {C1 product}
    bool UseNewFeature4 = false {C1 product}
    bool UseNewLongLShift = false {product}
    bool UseNiagaraInstrs = false {product}
    bool UseOSErrorReporting = false {pd product}
    bool UseOnStackReplacement = true {pd product}
    bool UsePSAdaptiveSurvivorSizePolicy = true {product}
    bool UseParNewGC = false {product}
    bool UseParallelDensePrefixUpdate = true {product}
    bool UseParallelGC = false {product}
    bool UseParallelOldGC = false {product}
    bool UseParallelOldGCCompacting = true {product}
    bool UseParallelOldGCDensePrefix = true {product}
    bool UsePerfData = true {product}
    bool UsePopCountInstruction = false {product}
    intx UseSSE = 99 {product}
    bool UseSSE42Intrinsics = false {product}
    bool UseSerialGC = false {product}
    bool UseSharedSpaces = true {product}
    bool UseSignalChaining = true {product}
    bool UseSpinning = false {product}
    bool UseSplitVerifier = true {product}
    bool UseStoreImmI16 = true {product}
    bool UseStringCache = false {product}
    bool UseTLAB = true {pd product}
    bool UseThreadPriorities = true {pd product}
    bool UseTypeProfile = true {product}
    bool UseUTCFileTimestamp = true {product}
    bool UseUnalignedLoadStores = false {product}
    bool UseVMInterruptibleIO = true {product}
    bool UseVectoredExceptions = false {pd product}
    bool UseXMMForArrayCopy = false {product}
    bool UseXmmI2D = false {product}
    bool UseXmmI2F = false {product}
    bool UseXmmLoadAndClearUpper = true {product}
    bool UseXmmRegToRegMoveAll = false {product}
    bool VMThreadHintNoPreempt = false {product}
    intx VMThreadPriority = -1 {product}
    intx VMThreadStackSize = 0 {pd product}
    intx ValueMapInitialSize = 11 {C1 product}
    intx ValueMapMaxLoopSize = 8 {C1 product}
    bool VerifyMergedCPBytecodes = true {product}
    intx WorkAroundNPTLTimedWaitHang = 1 {product}
    uintx YoungGenerationSizeIncrement = 20 {product}
    uintx YoungGenerationSizeSupplement = 80 {product}
    uintx YoungGenerationSizeSupplementDecay = 8 {product}
    uintx YoungPLABSize = 4096 {product}
    bool ZeroTLAB = false {product}
    intx hashCode = 0 {product}

    展开全文
  • 一个由 C/C++ 编译的程序占用的内存分为以下几个部分 : 栈区( stack ) ——由编译器自动分配释放,存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。其操作方式类似于数据结构中的栈; 堆区( ...
  • MapReduce作业运行过程中内存溢出错误分类 1、 Mapper/Reducer阶段JVM内存溢出(一般都是堆) 1) JVM堆(Heap)内存溢出:堆内存不足时,一般会抛出如下异常: 第一:“java.lang.OutOfMemoryError:” GC overhead...
  • Java内存划分分配

    千次阅读 2018-10-18 15:03:41
    最后学习一下Java堆内存代划分和内存分配。 Java内存区域划分 首先通过一张图来看一下Java虚拟机是如何划分内存空间的。 程序计数器:是一块较小内存,可以看作是当前线程所执行的字节码的行号指示...
  • 基础知识篇——堆内存和内存

    万次阅读 多人点赞 2018-11-01 09:05:00
    数据结构中的堆栈 栈 是一连续储存的数据结构,具有先进后出的性质。 通常的操作有入栈(压栈),出栈栈顶元素。想要读取栈中的某个元素,就是将其之间的所有元素出栈才能完成。 堆 是一非连续的树形储存...
  • ①引用计数 对象增加一个引用时,引用数+1。减少一个时,引用数-1。当进行垃圾回收时,只回收引用数0的对象。...将内存分为2个区域(区域a区域b),一个区域空着(区域a),另一个区域(区域b)放
  • 3.1为什么会产生内存泄漏 3.2 解决方式 1.介绍 作为一个Java开发者,想必大家都听说过:内存溢出和内存泄漏。但真正了解的人,也许寥寥无几。亦或是,认为两者就是同一概念的人,也是大有人在。之前有...
  • Tomcat调优总结【内存和线程】

    万次阅读 2017-11-13 11:31:13
    Young 区被划分三部分,Eden 区和两个大小严格相同的 Survivor 区,其中 Survivor 区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在 Young 区间变满的时候,minor GC 就会将存活的...
  • 为什么4G物理内存,可用只有3G?

    千次阅读 2011-08-15 14:18:04
    XP或VISTA都分两种系统,一种是32位的,一种是64位的。我们常见的都是32位的。在微软的设计里面,32位系统最高只能支持到4GB的存储容量,注意:是最高4GB的总容量,不是指内存4GB。 而主板里面的其它设备如系统...
  • JVM——内存管理垃圾回收

    万次阅读 多人点赞 2016-07-12 21:05:30
    Java与C语言相比的一个优势是,可以通过自己的JVM自动分配回收内存空间。垃圾回收机制是由垃圾收集器Garbage Collection来实现的,GC是后台一个低优先级的守护进程。在内存中低到一定限度时才会自动运行,因此垃圾...
  • Jvm内存溢出的几情况

    千次阅读 2017-07-27 23:43:24
    关于Jvm内存溢出的几情况
  • •Java内存模型 •内存间交互操作 •volatile型变量 •先行发生原则 •写在前面 在正式讲解之前呢,我们先来讨论讨论硬件的效率与一致性。这里我们讲讲物理机对并发的处理方案,因为物理机遇到的并发问题与...
  • 详解为什么32位系统只能用4G内存

    千次阅读 多人点赞 2018-08-12 14:26:24
    既然是详解, 就从最基础的讲起了. 1. Bit(位) Bit计算机是计算机最小的存储单位, 大家都知道计算机实质上都是用二进制数0... 也就是说bit只有2值, 0 或者 1, 所以1个bit能存放1个布尔类型的值(boolean,是或者否)....
  • SSD和内存数据库技术

    千次阅读 2016-04-26 10:57:47
    本文阅读书籍Next Generation Databases: NoSQL, NewSQL, and Big Data 第7章: The End of Disk? SSD and In-Memory Databases的笔记。 磁盘已死?比尔.盖茨在1981年曾说过: 640K of memory should be enough ...
  • 日期 内核版本 架构 作者 GitHub CSDN 2016-08-31 Linux-4.7 ...1 前景回顾前面我们讲到服务器体系(SMP, NUMA, MPP)与共享存储器架构(UMANUMA)1.1 UMANUMA两种模型共享存储型多处理机有两种模型
  • 栈的区别 (stack and heap)一般认为在c中分为这几个存储区 1栈 - 有编译器自动分配释放 2堆 - 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 3全局区(静态区),全局变量静态变量的存储...
  • Linux内存描述之内存页面page--Linux内存管理(四)

    万次阅读 多人点赞 2016-08-31 14:18:44
    日期 内核版本 架构 作者 GitHub CSDN 2016-08-31 Linux-4.7 ...1 前景回顾1.1 UMANUMA两种模型共享存储型多处理机有两种模型 均匀存储器存取(Uniform-Memory-Access,简称UMA)模型 非均匀存储器
  • 日期 内核版本 架构 作者 GitHub CSDN 2016-08-31 Linux-4.7 ...1 前景回顾前面我们讲到服务器体系(SMP, NUMA, MPP)与共享存储器架构(UMANUMA)1.1 UMANUMA两种模型共享存储型多处理机有两种模型
  • 电脑内存条C14C16的区别是什么

    万次阅读 2019-09-12 09:47:59
    也就是响应时间不同,单位时钟周期。 2、性能不同 其他条件相同的情况下,数字越小性能越好。 3、价格不同 其他条件相同的情况下,数字越小价格越高。 4、颗粒不同 内存中使用的颗粒不同,数字越小颗粒越好...
  • 操作系统为什么用户态内核态

    万次阅读 多人点赞 2015-09-05 15:34:40
    比如:清内存、设置时钟等。如果所有的程序都能使用这些指令,那么你的系统一天死机n回就不足为奇了。所以,CPU将指令分为特权指令非特权指令,对于那些危险的指令,只允许操作系统及其相关模块使用,普通的应用...
  • JVM内存模型垃圾回收机制

    千次阅读 2019-06-26 08:00:00
    其中方法区堆是所有线程共享的,虚拟机栈、本地方法栈程序计数器则线程私有的。 有的博客称方法区是永久代,那是因为前者是JVM的规范,而后者则是JVM规范的一实现,并且只有HotSpot才有永久代, JDK8中...
  • 常见的内存溢出的三情况

    千次阅读 2017-02-28 11:16:10
    常见的内存溢出的三情况: 1)JVM Heap(堆)溢出:java.lang.OutOfMemoryError: Java heap space JVM在启动的时候会自动设置JVM Heap的值, 可以利用JVM提供的-Xmn -Xms -Xmx等选项进行设置。Heap的大小是...
  • 种内存泄露检测工具的比较

    万次阅读 2014-10-07 01:44:49
    内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的、复杂的应用程序中,内存泄漏是常见的问题。当以前分配的一片内存不再需要使用或无法访问时,但是却并没有释放它,这时...
  • 程序的内存分配之堆栈的区别

    万次阅读 多人点赞 2015-10-01 09:38:52
    堆栈概述  在计算机领域,堆栈是一个不容忽视的概念,堆栈是两种数据结构。堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入删除。在单片机应用中,堆栈是个特殊的存储区,...
  • JVM主内存和工作内存的关系

    千次阅读 2017-06-27 21:23:50
    java线程内存分析 转载自博客 http://blog.csdn.net/zhuyijian135757/article/details/51335121 线程、工作内存、主内存三者之间的交互关系图:   key edeas 所有线程共享主内存 每个线程...
  • 虚拟内存和物理内存

    千次阅读 2014-04-02 22:26:16
    1、用户编制程序时使用的地址称为虚地址或逻辑地址,其对应的存储空间称为虚存空间或逻辑地址空间;而计算机物理内存的访问地址则称为实...从本质上来说,物理内存是代码数据在其中运行的窗口。 3、虚拟内存::使得
  • 要明白这个首先要知道什么是保护模式实模式。 以前的操作系统是实模式,例如dos。每个时候只有一个进程在跑,这个进程使用全部的物理内存。 后来发展到保护模式,时多进程。一个CPU上跑多个进程, 但进程不...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 589,118
精华内容 235,647
关键字:

内存可分为什么和什么两种