jvm相关。

首先java程序运行流程

java程序 -》 遍译器 -》 .class文件 -》  类加载器 -》 加载classloader -》 二进制文件 

jvm分为类加载器 执行引擎 数据区(方法区 栈  堆 等等)

类加载器

jvm的类加载器大致分为 bootstrap classloader -> extension classloader -> system classloader ->userdefine classloader

bootstrap 主要负责将 Java_Home/lib下面的类库加载到内存中

ext负责Java_Home /lib/ext加载

由于哪怕完全限定名是相同的,如果类加载不一一样。他们也不是同一个类

类加载流程  遇到类加载请求后,从bootstrap开始找。然后ext然后system.最后才是Userdefine

这种的好处是。 自己定义的类。比如String 在加载的过程不会覆盖系统的java.lang.string这个类。导致整个程序出问题。保护jvm 的Jdk代码正确

显然每个系统类加载器之间并非继承关系,而是组合关系

所有以上的这个东西叫双亲委派模型

为啥起这个名字 可能跟他的英文名有关 Parent Delegation Model

在java代码中。通过new方式。jvm会隐式加载.class  隐式加载属于硬编码 通过jvm加载相关的类

.forname() jvm会显示加载.clss  显示加载 通过反射方式 动态加载类。可以选择加载器。绕过jvm的权限检查(声明为private 的方法想调用)

jvm内存模型

  • 方法区:存储静态变量。常量(有专门的常量区,比如专门的字符串常量池,string).方法 接口。类型信息等元数据信息。
  • 栈:每个线程私有。当有新的方法。栈里压入栈帧,局部变量表,方法入口 都存在里面。方法执行完 栈帧出栈。销毁不可达的对象
  • 堆:类得实例。全局变量。
  • 本地方法栈:调用系统的方法
  • register程序计数器:线程私有,指示代码执行到哪一行了。

堆占用内存的一部分。对象的new就会分配一定的空间。如果清理不及时会出现内存溢出。如果内存得不到回收 会出现内存泄露

堆的区域组成

 young代 old代 永久代

young代 分为eden区 两个survive区域  s0 s1大小一般相等 存放短生命周期的对象,95%对象都是使用一下就用不到了。这些放到young代为了及时被清理 释放内存空间

old代 由young升级进入的存放的对象

永久代 方法区的都在永久代。永久代不代表不会清理

对象存活

  对象首先被存放在eden区,当eden区域满的时候,进行一次minor gc 停止-复制的GC方法 停止用户线程,将存活的对象复制到s0,清理死掉的对象,s1为空,第二次,当eden区域满的时候,清理死掉的对象,将eden区域存活的对象放置到s1,s0的对象或者升级到old区或者复制到s1,s0为空,s0s1直到来回一定次数的对象,晋升到老年代。老年代慢的时候回进行full gc,full gc

是采用标记整理。 标记 死掉的对象,然后边清除,边整理对象到一侧,保证内存的连续性。分配内存空间的时候比较快。

CC算法

垃圾收集器

parell收集器。多线程 。采用停止复制的方法 在年轻带使用 收集的时候 用户线程会停止。也就是会有停顿。但是关注吞吐量(垃圾收集时间。应用程序运行时间)

cms收集器。多线程 采用标记清理。 在年老带。会产生大量内存碎片。

G1收集器。多线程。采用标记整理。年轻代还是年老代都应用。 1不会产生空间碎片。清理的同时把对象移动到年老带的另一边。2将内存区域分成好几块。然后看哪个垃圾多。哪个就处理。减少了卡顿时间。

调整eden代 s0s1代。年老带的大小让他们达到一定的效果

常见关于内存溢出的原因:1从数据库取出的对象过多。比如一次取出几百万条。2内存泄露3死魂环

内存泄露。长生命周期对象引用短生命周期对象的引用。导致短生命周期的对象得不到释放。比如方法的局部变量。引用却写成全局变量。就算方法结束了。局部变量也得不到释放。就是内存泄露。那调用一次方法。就产生一次内存泄露

posted @ 2018-12-11 17:05  saveworld_niub  阅读(153)  评论(0编辑  收藏  举报