美文网首页
jvm小总结

jvm小总结

作者: f22448cd5541 | 来源:发表于2019-02-13 14:21 被阅读0次

    为什么要了解JVM

    作为java 程序员开发,如果想要更好的优化程序的话,必须要对jvm的整个原理非常了解,这样才能在高并发的场景中,根据自己的业务需求去配置相应的jvm。

    jvm内存分配

    从功能角度来考虑jvm内存划分可以分为:

    • 堆: 主要是创建对象或者数组分配的内存区。也是java里最大的一块内存区,也经常会gc回收垃圾对象释放内存。
    • 栈: 这里分为虚拟机栈和本地方法栈。
      • 虚拟机栈:主要是线程执行一个方法的时候会单独分配的一块内存(存放局部变量,执行的方法一些元信息等等),这也是方法天然线程安全的原因。(方法的进入和退出对应的栈帧的入栈和出栈)
      • 本地房发栈:在jvm有些方法比较特殊是native方法,这类方法一般是调用本地系统接口,执行的时候没有加载字节码这一过程,所以执行也与普通的方法不同。
    • 非栈:主要分为方法区和常量池。
      • 方法区:class在被加载的时候,方法的原始数据会存在在这个内存区。基本上不会存在被回收的可能。因为它属于模板数据,虚拟机栈里运行线程会加载方法区的方法元数据。
      • 常量池: 主要存放jvm加载字节码的时候,static区分配的内存。当然运行以后也可以继续向常量池增加数据,例如: String 里的 intern()方法,可以将字符创放入常量池。
    • 程序计数器区: 主要是记住线程指令的地址。当还没执行的线程,记录的是起始地址。运行的线程记录的是当前执行指令的地址。(记录后便于cpu时间片切换)

    注: 程序计数器、虚拟机栈、本地方法栈 随着线程而生,随着线程结束而灭。

    常用的jvm参数

    • 设置堆的大小(最大): -Xmx10M
    • 设置堆的大小(最小): -Xmn10M
    • 设置显示gc回收日志: -verbose:gc
    • 让虚拟机的内存异常日志打印出来(会有一个hrrof的文件):-XX:+HeapDumpOnOutOfMemoryError
    • 栈容量设置:-Xss10M

    线程OOM(java.lang.OutOfMemoryError)

    -Xss10M 固定的时候,每启动一个线程的时候就会占用虚拟机栈的空间,所以每个线程分配的虚拟机栈的容量越大,那么能够启动的线程数就越少。

    代码演示:

    /**
     * <p>
     *      测试虚拟机栈 java.lang.OutOfMemoryError
     * </p>
     *
     * @author robinyang
     * @date 2018.10.03
     *
     * @see StackOverflowError
     */
    public class Test04 {
    
        public static void main(String[] args) {
            for (int i = 0; i < 1000; i++) {
                new Thread(new OOMThread()).start();
                System.out.println(i);
            }
        }
    
    
        public static class OOMThread implements Runnable {
    
            public void run() {
                byte[] bytes = new byte[10240];
                try {
                    Thread.sleep(100000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    当启动七百多的时候就会出现:

    Exception in thread "Thread-757" Exception in thread "Thread-761" 
    Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
    Exception in thread "Thread-758" Exception in thread "Thread-760" Exception in thread "Thread-762" Exception in thread "Thread-763" *** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message can't create byte arrau at JPLISAgent.c line: 813
    

    增强类导致OOM

    方法区一般存放的是Class相关信息,比如 类名、访问修饰符、常量池、字段描述、方法描述等。想要测试这些区域OOM 可以通过产生大量类去填充方法区即可。可以通过动态反射和CGLib可以产生大量的动态类。

    总结:在一些框架,如:SpringHibernate等等,在对类进行增强的时候,经常会产生很多类,类越多,导致方法区的内存占用比较大,出现OOM。还有jvm上的动态语言为了实现动态特性会持续创建类,也会导致方法区内存占用过大,出现OOM。

    直接内存默认值

    DirectMemory 这块内存跟元数据的直接内存是两块不一样的内存,这里的内存可以存放我们程序运行时的数据。当我们不设置直接内存大小的时候,默认和Java堆内存一样大小 -Mmx5M 一样大。

    当然,我们可以直接设置堆外内存: -XX:MaxDirectMemorySize=10M

    相关文章

      网友评论

          本文标题:jvm小总结

          本文链接:https://www.haomeiwen.com/subject/djqdeqtx.html