A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

java内存分配
  JVM启动时,会在内存中占用一块空间。这块内存空间被分为:方法区、虚拟机栈、本地方法栈、堆、程序计数器。
  这些内存区域组成java运行时数据区。
  程序计数器:一块较小的内存,为当前线程所执行的字节码的行号指示器。字节码的解释执行需要通过这个计数器的值来取下一条指令。
                     而分支(if,switch),循环(for,while),跳转(break,continue),异常处理(try...catch),线程恢复都依赖计数器完成。
     对于单核CPU来说,多线程是通过线程快速切换执行来完成的。而为了多线程切换后能快速恢复正确位置,每个线程有一个独立的程序计数器,所以程序计数器是线程私有内存。
      此内存区域是唯一一个不存在内存溢出的区域。执行native方法时,计数器为空。
  虚拟机栈:即我们常说的栈内存。线程私有,生命周期与线程相同,用于描述方法的执行。一个方法被调用至执行完成,对应入栈-出栈。
       栈内存中存储:局部变量,操作栈,动态链接,方法出口
       局部变量表:栈内存中存储局部变量的部分:存储八种基本数据类型、对象的引用(记录地址)、returnAddress(字节码指令地址)
       栈内存在编译时就确定了大小,不会再改变(long,double占2个内存空间,其他占1个内存空间)
       栈内存可能出现的异常:StackOverflowError(单线程内存溢出),OutOfMemoryError(由于每个线程都有私有栈,线程越多,栈内存总量越大,超出规定值溢出)
  本地方法栈:同虚拟机栈,为native方法服务
  :线程共享内存,虚拟机启动时创建,用于存放对象,数组。堆内存的特点是垃圾清理。可能出现异常OutOfMemoryError:对象过多。
  方法区:线程共享内存,存储虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码。可能出现异常OutOfMemoryError。
  常量池:方法区的一部。编译期生成的各种字面量,符号引用在类加载后存入常量池。
  1.                 Object obj = new Object();
  2.                 //Object obj存入栈内存的变量表
  3.                 //new Object()存入堆内存
  4.                 //而Object的类加载信息(类型,父类,接口,方法)存入方法区
复制代码

java的垃圾回收机制
  程序计数器,虚拟机栈,本地方法栈三块内存生存周期与线程相同,这几块内存从分配到回收都是确定的,不存在垃圾回收问题。垃圾回收只涉及堆内存和方法区,这两块内存的分配回收都是动态的。
  堆内存对象回收算法:一个基本的算法是引用计数器,即有一个引用指向对象,该对象的引用计数器+1,引用失效,引用计数器-1,当引用计数器为0时,启动垃圾回收。这种算法简单,高效,但存在极大问题。当A对象的属性引用B对象,B对象的属性引用A对象,除此之外两个对象再无引用。实际上这两个对象已经不可能被访问,但由于互相引用,导致永远不可能被回收,造成内存泄漏。由于上述问题,垃圾回收机制不会使用引用计数器算法。
  JVM实际回收算法:根搜索算法:取一系列对象作为起始点,从这些节点上开始向下搜索,搜索所走过的路径称为引用链。当一个对象到起始点没有任何引用链连通时,说明该对象永远不可能到达,启动垃圾回收。
  可作为起始点的对象:栈中本地变量表中引用的对象;方法区中静态类属性引用的对象;方法区中常量引用的对象;本地方法区中native方法引用的对象。
  四种引用:强引用,软引用,弱引用,虚引用
      JDK1.2之前,只存在引用,非引用。引用的定义即引用类型数据中存储的是一块内存地址,那这块内存即为引用。JDK1.2之后对引用进行了细化,当内存是足够的,一些引用可以存储于内存中,当内存在垃圾回收之后还非常紧张时,这些引用可以抛弃。
       基于上述思想,划分出四种引用:
            强引用:Object obj = new Object();这类引用在失效前永远不会被垃圾回收
            软引用:系统在将要发生内存溢出之前,扫描软引用并回收,如果软引用都被回收,内存还是不够,才抛出内存溢出
            弱引用:一次垃圾回收之后,下次垃圾回收之前的垃圾,一旦垃圾回收,这些弱引用必定会回收
            虚引用:该引用获取不到引用对象,其作用仅仅是在这个对象被回收时,获取一个通知(知道哪个对象被回收了)
  finalizer()方法
       Object的方法,所有对象都有。一个对象的回收,经过两次搜索。第一次确定该对象是垃圾,之后会检查finalizer方法是否被重写,未重写则对象回收。若finalizer方法被重写,会将对象放入一个序列中,由虚拟机执行finalizer方法。此时,该对象有一次自救的机会,即在finalizer方法内部重新建立有效的引用,引用建立成功,则该对象又活了。自救失败,则垃圾回收。finalizer方法只会被执行一次,自救一次后,再垃圾回收,不会再判断finalizer方法。该方法的使用是极其不被推荐的,建议大家忘记这个方法。
  方法区中的垃圾包括两部分:废弃常量,无用的类
          废弃的常量:与堆内存中的对象相似,没有任何引用的常量即可执行垃圾回收
          无用的类:必须同时满足三个条件:
                   1、该类所有的实例已经被回收
                   2、该类的classloader已经被回收了
                   3、该类的Class对象无引用,即该类不可能被反射
类加载
  从类加载至卸载经过7个阶段:加载,验证,准备,解析,初始化,使用,卸载。其中验证,准备,解析合称连接。
  类执行初始化的条件:new对象,读取/设置一个类中的静态字段(非final的,final的在常量池中),调用类中的静态方法。
                                    反射时。
                                    初始化一个类时,发现其父类未初始化,则初始化父类。
                                    启动虚拟机执行一个主类(带main方法的类)。
    以上四种情况称为主动引用,而被动引用不会引发类初始化
  被动引用:通过子类调用父类静态字段,子类不被初始化。
                   通过定义类类型数组,类不会被初始化。
                   常量在常量池中,与类无关,类不会初始化。
  加载执行过程:
    1、获取字节码二进制流(不一定是class文件)
    2、将字节流所代表的静态存储结构转化为方法区的运行时数据结构
    3、在堆内存中生成一个Class对象,作为静态数据入口
  验证执行:检验代码是否可用,是否安全(不会对系统造成危害)
  准备:为类变量(static)分配内存,设置类变量初始值。初始值为类型默认值,不是第一次赋的值
  解析:将常量池中的符号引用替换为直接引用
  初始化:执行所有静态变量赋值,执行static代码块
类加载器
  JVM需要的是一个字节码文件的二进制流,而不是一个文件。该流的获取动作称为类加载器。
    java中判断两个类是否相同,首先看是否由同一个类加载器加载,若不是,即使文件是同一个,也不是同一个类(包含equals()和instanceof)
静态绑定和动态绑定
  静态绑定:在编译过程中已经绑定,与对象无关,哪个类型访问,调用哪个类的成员。java中成员变量(类变量,实例变量),被final,static,private修饰的方法,构造方法都是静态绑定。
  动态绑定:运行时,根据对象的类型绑定,这也是多态的体现。java中非静态绑定的方法都是动态绑定。

评分

参与人数 1技术分 +3 收起 理由
杨佳名 + 3

查看全部评分

1 个回复

倒序浏览
谢谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马