javaJVM

加载器

1.虚拟机加载器

2.启动类(根)加载器

3.扩展类加载器   (ExtClassLoader  \jre\lib\ext)

4.应用程序加载器   (AppClassLoader)

342c7c2798fc4687a210a1841a15134a.jpg

1223ac3e7b0649d3b61881721e577b4f.jpg

双亲委派机制(安全)

App->Ext->Boot(最终执行)

1.类加载器收到类加载器的请求

2.将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载器。

3.启动类加载器检查是否能够加载当前这个类,能加载就结束,使用当前的加载器,否则,抛出异常,通知子加载器进行加载。

4.重复步骤3。

沙箱安全机制

java安全模型的核心就是java沙箱(sandbox),沙箱是一个限制程序运行的环境。沙箱机制就是将java代码限定在虚拟机特定的运行范围中,并严格限制代码对本地系统资源的访问。通过这样的措施来保护对代码的有效隔离,防止对本地系统造成破坏,沙箱主要限制系统资源访问。

组成沙箱的基本组件:

1.字节码校验器

确保java类文件遵循java语言规范,这样可以帮助java程序实现内存保护。但并不是所有的类文件都会经过字节码校验,比如核心类。

2.类装载器

其中类装载器在3个方面对java沙箱起作用

它防止恶意代码去干涉善意的代码(双亲委派机制)

它守护了被信任的类库边界

它将代码归入保护域,确定了代码可以进行哪些操作

Native

凡是带了native关键字的,说明java的作用范围达不到了,回去调用底层c语言的库。

会进入本地方法栈,调用本地方法接口(JNI)。

JNI作用:扩展java的使用,融合不同的编程语言为java所用。最初的目的是融合c、c++.

它在内存区域中专门开辟了一块标记区域:Native Method Stack,登记native方法,在最终执行的时候,加载本地方法库中的方法通过JNI

程序计数器(Program Counter Register)

每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向一条指令的地址,即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。

方法区(Method Area)

方法区是被所有线程共享,所有子段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,简单说,所有定义的方法的信息都保存在该区域,此区域属于共享区间。

静态变量、常量、类信息(构造方法,接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法区无关。

栈内存,主管程序的运行,声明周期和线程同步,线程结束,栈内存也就是释放,对于栈来说,不存在垃圾回收问题。

栈中可以放8大基本类型+对象引用+实例的方法

每个栈帧包括:方法索引、输入输出参数、本地变量、ClassFile:引用、父帧、子帧。

如果栈满了:Stack OverflowError

080686ba30874f81b59e2eb29cf77fe6.jpg

Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的,类加载器读取了类文件后,一般会把什么东西放到堆中? 类、方法、常量、变量...保存我们所有引用类型的真实对象。

堆内存中还要细分为三个区域:

新生区(伊甸区)young/new

养老区 old

永生区 Perm

b7aeaefda7e747629f5ede273cd4fdf9.jpg

在JDK1.8以后,永久存储区改了名字(元空间)

新生区:

        类诞生和成长的地方,甚至死亡;

        伊甸区,所有的对象都是在伊甸区new出来的

        幸存区(from, to)

养老区

永久区:

        关闭虚拟机就会释放这个区域的内存,这个区域常驻内存的,用来存放JDK自身携带的Class对象。Interface元数据,存储的是java运行时的一些环境或类信息,不存在垃圾回收

JDK1.6之前:永久代,常量池是在方法区

JDK1.7:永久代,但慢慢的退化了,去永久代,常量池在堆中。

JDK1.8之后:无永久代。常量池在元空间。

一个启动类,加载了大量的第三方jar包。Tomcat部署了太多的应用,大量动态生成的反射类,不断的被加载,直到内存慢,就会出现OOM。

1175d63d506f4137a8592d5fe09cd610.jpg

解决OOM

1.尝试扩大内存,看结果

2.分析内存,看一下哪个地方出现了问题。

        (1)能够看到代码第几行出错,内存快照分析工具,MAT,Jprofiler

        (2)Dubug,一行行分析代码

MAT,Jprofiler作用:

        1.分析Dump内存文件,快速定位内存泄漏;

        2.获得堆中的数据

        3.获得大的对象。

GC:垃圾回收

JVM在进行GC时,并不是对这三个区域统一回收,大部分时候,回收都是新生代。

GC有两种:轻GC(普通的GC)(发生在新生代,偶尔在幸存区),重GC(全局GC)

幸存区有两个from和to,谁空谁是to

GC算法

引用计数法

每个对象都有计数器,计数器本身也会有消耗。(不高效,一般不用)

复制算法

1.每次GC都会将Eden活的对象移动到幸存区,一旦Eden区被GC后,都会是空的。

2.当一个对象经历了15次GC,都还没有死,会进入老年区。

        通过这个参数可以设定进去老年代的时间

        -xx : -xx :MaxTenuringThreshold=99

好处:没有内存碎片

坏处:浪费了内存空间,多了一半空间永远是空。假设对象100%存活(极端情况)

复制算法最佳使用场景:对象存活度较低的时候(新生区)

标记清除算法

标记:扫描这些对象,对活着对象进行标记

清除:对没有标记的对象进行清除

优点:不需要额外的空间

缺点:两次扫描,严重浪费时间,会产生内存碎片

标记压缩算法

压缩:防止内存碎片产生,再次扫描,向一端移动存活的对象,多了一个移动成本。

标记清除压缩:先标记清除几次,再压缩。

总结

                                                        高->低

内存效率:复制算法 -> 标记清除 -> 标记压缩(时间复杂度)

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

内存利用率:标记压缩算法 = 标记清除算法 -> 复制算法

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

分代收集算法(generation) 当前主流 JVM 都采用分代收集(Generational Collection)算法, 这种算法会根据对象 存活周期的不同将内存划分为年轻代、老年代、永久代,不同生命周期的对象可以采取不同 的回收算法,以便提高回收效率。

年轻代:存活率低(复制算法)

老年代:区域大,存活率高(标记清除(内存碎片不是太多)+标记压缩混合实

JMM(Java Memory Model)

1.什么是JMM:

java内存模型

2.作用:

缓存一致性协议,用于定义数据读写的规则。

JMM定义了线程工作内存和主存之间的抽象关系:

线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory)。线程工作内存每个线程都有自己的工作区域,是从主内存拷贝的。

解决共享对象可见性这个问题:volilate

071c08eabd8f44b68a487398ce9b5d79.jpg

3.如何学习

JMM:抽象的概念,理论。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值