• 三:JVM(重点)


    1.类加载器(将字节码文加加载到方法区  这里有一个验证的过程,错误的class将会被jvm吐出)重点

      1.1 虚拟机加载器

        启动类加载器:Bootstrap   通过getClassLoder获得的是Null。例如object类和String类的类加载器就是null因为权限不够

        扩展类加载器:extension   javax开头的包就是扩展的加载器的包

        应用程序类加载器:Appclassloder 自己写的类的加载器。java也叫系统类加载器,加载当前应用的classpath的所有类

      1.2 用户自定义加载器

        Java.lang.classloader的子类用户可以定制类的加载方式。

      1.3 沙箱安全机制:

        1.先去启动类里面找,找的到就用,找不到就去扩展类加载器中去用,如果还是找不到就去应用程序类加载器中去用:例如下面会包错找不到main方法

        

       1.4双亲委派机制:

          当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。
          采用双亲委派的一一个好处是比如加载位于rt,jar包中的类java.lang.Object, 不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这 样就保证了使用不同的类加载器最终得到的都是同样一个 Object对象。

    2.执行引擎执行

    3.本地接口(重点)native只有声明没有实现 因为实现不在JAVA中而在第三方(底层)

      本地方法接口native interface:用native标注的方法就已经超出了JAVA的管辖范围就要等待C或者底层第三方函数库去实现

           本地方法加载到本地方法栈中

    4.PC寄存器:程序计数器(就相当于程序运行顺序表每个各自存着下一条代码的内存地址。)

      记录了方法之间的调用和执行情况,类似排班值日表,用来存储指向下一条指令的地址,也即将要执行的指令代码,他是当前线程所执行的字节码的行号指示器

    5.方法区:

      5.1 他存储了每一个类的结构信息(模板)

      5.2 方法区是规范,在不同的虚拟机里头实现是不一样的。最典型的就是永久代(PermGen Space)和元空间(Metaspace)Static就应该是在方法区中的吧 方法区中的数据在JVM关闭后才会清除

     6.栈管运行,堆管存储

      程序=算法+数据结构

      工作上:程序=框架+业务逻辑

    7.栈是线程创建时创建,线程结束内存就会释放,对于栈来说,不存在垃圾回收的问题,只要线程一结束栈内的内存就over,生命周期和线程一致,是线程私有的。8种基本类型的变量+对象引用的变量+实例方法都是在函数的栈内存中分配。

      栈存储3类数据:

        本地变量:输入参数和输出参数以及方法内的变量

        栈操作:记录出栈,入栈的操作

        栈帧数据:包括类文件,方法等

    8.JAVA方法在JVM栈空间中叫做“栈帧”

    9.exception是错误,不是异常

    10.Hotspot是使用指针的方式来访问对象;Java堆中会存放访问类元数据的地址,reference储存的就直接是对象的地址

    11.堆(heap)内存(逻辑上分为三个部分:新生,养老,永久代默认新生代内存8:1:1;物理上:新生+养老):

        1. new 新生区   1/3的堆空间

          1.1.伊甸园(Eden Space)  又称 young区

          1.2.幸存者0区 (Survivor 0 Space)  又称  from区

          1.3.幸存者1区 (Survivor 1 Space)  又称  to区

        2. old 老年代:15次的后才会到老年区可以自己修改,但是最大不能超过15  2/3的堆空间

        3. 元空间 (方法区是个规范:元空间实现   永久储存空间有的人也成永久带)

    12.minorGC机制(GC之后有交换,谁空谁是to)  新生区的GC

       复制->清空- >交换

    13 majorGC机制 养老区的GC

    14 JAVA8以后的元空间并不在虚拟机中而是在使用本机物理内存

    15 堆内存调优(重点)

      -Xms  设置JVM堆内存的初始分配大小,默认为物理内存的1/64

      -Xmx  JVM堆内存最大分配内存,默认为物理内存的1/4

      -XX:+PrintGCDetails  输出详细的GC处理日志

      重点:必须把Xms调到-Xmx一样大,避免GC和应用程序争抢内存,内存忽高忽低

      eclipse在run config里面调VM参数就可以了

      代码查看:

      

    package testMain;
    
    
    
    public class JVMRun {
        public static void main(String[] args) {
            System.out.println(Runtime.getRuntime().availableProcessors());
            long maxMemory = Runtime.getRuntime().maxMemory(); // 返回JAVA虚拟机试图使用的最大内存量
            long totalMemory = Runtime.getRuntime().totalMemory(); //返回JAVA虚拟机中的内存总量
            System.out.println("MAX memory = "+maxMemory+"(字节), "+maxMemory/1024/1024+"MB");
            System.out.println("total memory = "+totalMemory+"(字节), "+totalMemory/1024/1024+"MB");
    
            byte[] bytes = new byte[40*1024*1024];
            
            
        }
    }
    JAVA堆内存调参

    16:可能有人有疑问:为什么调内存只调堆,不调栈呢?

      还是那句话,堆管存储,栈管运行(栈需要的内存很小因为,每一条指令的操作都是pc寄存器在引导,出栈入栈也是)

      虚拟机栈有一帧帧的 栈帧组成,而栈帧包含局部变量表,操作栈等子项,那么线程在运行的时候,代码在运行时,是通过程序计数器不断执行下一条指令。真正指令运算等操作时通过控制操作栈的操作数入栈和出栈,将操作数在局部变量表和操作栈之间转移。

    17.GC日志信息

      GC一般发生在young区,产生GC是因为new失败了,内存不够用了,所以才发生垃圾回收机制 

      发生OOM一般是full GC失败,fullGC在老年区

    18 GC

      GC是什么(分代收集算法)

        1.次数上频繁收集young区

        2.次数上较少收集old区

        3.基本不动元空间

      

        Minor GC(普通GC) 和Full GC(全局GC)的区别: full GC要比 MinorGC慢10倍以上,原因是,Full GC要扫描Old区,Old区空间大,要扫描的东西多,所以才慢

        

        4算法:

          1.引用计数法  (后台有一个大型的计数器在计算每一个对象的引用次数)

              缺点:每次对对象赋值时均要维护应用计数器,且计数器本身也有一定的消耗

                   较难处理循环引用

          2.复制算法 copying

              用在:年轻代中使用的是minor GC,这种GC算法采用的是复制算法,复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。

              优点:复制算法不会产生内存碎片(也就是Form 和to的交换过程)

              缺点:浪费太多的内存,如果对象存活率高的话,就很麻烦,因为要把所有都复制一遍

          3.标记清除 Mark - Sweep

               用在:老年代  一般是由标记清除或者是标记清除与标记整理的混合实现

               原理:算法分成标记和清除两个阶段,先标记出要回收的对象,然后统一回收这些对象(解决浪费空间的问题)用通俗的话解释一下标记清除算法,就是当程序运行期间,若可以使用的内存被耗尽的时候,GC线程就会被触发并将程序暂停,随后将 要回收的对象标记- -遍,最终统一回收这些对象,完成标记清理工作接下来便让应用程序恢复运行

                    

               优点: 不需要额外的空间

               缺点: 两次扫描(标记一次清除一次),耗时严重

                  会产生内存碎片(内存不连续)

          4.标记压缩  Mark - Compact (慢工出细活,理论上最好的算法,但是耗时)

            原理 : 1.标记 (与标记清除一样会先标记在清除)  2.压缩:再次扫描,并在一端滑动存活对象(优点没有内存碎片,可以利用dump   缺点:需要移动对象的成本)

            用处:老年代一般是由标记清除或者是标记清除与标记整理的混合实现

          小总结:

              内存效率:复制算法>标记清除算法>标记整理算法(此处的效率只是简单的对比时间复杂度,实际情况不一定)

              内存整齐度:复制算法=标记整理算法>标记清除算法

              内存利用率:标记整理算法=标记清除算法>复制算法

          没有最好的算法,只有合适的算法-----》分代收集算法

          年轻代:存货率低,所以使用复制算法

          老年代:区域大对象存活率高GC的次数比较少,一般由标记清除和标记整理混合实现

         面试题:

            1:JVM内存模型以及分区,需要详细到每个区放什么

            2.:堆里面的分区 :Eden,survival from to,老年代,各自的特点

            3.GC的三种收集方法:标记清除,标记整理,复制算法的原理与特点,分别用在什么地方

            4.Minor GC与full GC分别在什么时候发生

      19.JMM

      先看这两篇:

        https://www.jianshu.com/p/8a58d8335270

        https://zhuanlan.zhihu.com/p/29881777

      

      20:加载顺序

        父类的静态字段——>父类静态代码块——>子类静态字段——>子类静态代码块——>父类成员变量(非静态字段)——>父类非静态代码块——>父类构造器——>子类成员变量——>子类非静态代码块——>子类构造器

  • 相关阅读:
    ubuntu16.04安装ibus中文输入法
    apt --fix-broken install
    fuelgauge
    make flash FLASH_CONFIG=jtag_full
    使用android ndk编译boost动态库
    RK3288的gpio设置
    RK3288 GPIO 输出问题
    HDU-2586-裸LCA入门-tarjan离线
    uva-11324-SCC+dp
    HDU-2767-tarjan/Kosaraju求scc
  • 原文地址:https://www.cnblogs.com/BookMiki/p/14100452.html
走看看 - 开发者的网上家园