深挖基础知识
动静态代理的区别,什么场景使用
静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类
静态代理事先知道代理的是什么,而动态代理不知道代理什么东西,只有运行的时候才知道。
动态代理是实现JDK里的InvocationHandler接口的invoke方法。但注意的是代理的是接口,也就是你的业务类必须实现接口,通过Proxy里的newProxyInstance得到代理对象
AOP是基于动态代理实现的,比如著名的Spring框架、Hibernate框架等待都是动态代理的使用例子
Java中单例设计模式
分为懒汉式和饿汉式
饿汉式指的是在使用前就提前创建好,懒汉式指的是先声明变量名,然后什么时候使用再创建。
JVM垃圾回收机制和常见算法
GC在回收对象前必须发现那些无用的对象,那么如何发现呢?常用的搜索算法:
- 引用计数器算法(废弃)
指的是在创建每个对象时设置一个计数器,当有地方使用时,加1,当引用失效后,计数器减1,当计数器为0的时候,JVM就认为对象不再被使用。但是即使计数器实现简单,效率高,但不能解决循环引用的问题,同时也会带来额外的开销,从jdk1.1之后这个算法就被丢弃了 - 根搜索算法
根搜索算法是通过一些”GC Roots”对象作为起点,从这些节点开始搜索,搜索通过的路径成为引用链,当一个对象没有被GC Roots的引用链连接的时候,说明这个对象不可用
GC Roots对象包括:
- 虚拟机栈(栈帧中的本地变量表)中的引用对象
- 方法区域中的静态属性引用的对象
- 方法区域中常量引用的对象
- 本地方法栈中JNI中引用的对象
搜索到无用对象后,回收算法:
- 标记—清除算法(DVM使用的算法): 效率不高,清除后有许多不连续的空间
- 复制算法:将内存分成两块,当垃圾回收的时候,把存活的对象复制到另一块,然后把这个内存整个清除掉。但是由于每次只能使用其中的一半,所以内存利用率不高,现在的JVM用复制方法收集新生代,由于新生代大部分对象都是朝生夕死的,所以两块的内存比例不再是一半一半了!
- 标记—整理算法:适合收集存活时间比较久的对象,因为他是把存活的对象往内存的一端移动,然后回收边界以外的内存,从而提高了内存利用率。
- 分代收集: 根据对象的存活时间把内存分为新生代和老年代,每个代采用不同的垃圾回收算法。新生代使用复制算法,然后老年代采用标记整理算法。实现方式依赖于不同的虚拟机。
JVM内存结构
- 方法区: 静态分配,编译器将变量绑定到某个存储位置,而且绑定不会在运行时改变。常数池,源代码的命名常量、String常量和static变量保存在方法区
- Java Stack(栈): 一个栈的空间可能是连续的,也有可能不连续。栈中存储数据也是运行时确定的
- 堆分配: 以任意的顺序,在运行时进行存储空间分配和收回的内存管理模型。堆存储的数据通常是大小,数量和生命期在编译是不能确定的
JAVA内存分配
- 基本数据类型直接在栈空间分配
- 方法的形式参数,直接在栈空间分配,当方法调用完从栈空间回收
- 引用数据类型,需要通过new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量
- 方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用结束之后从栈空间回收
- 局部变量通过new出来的,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待GC回收
- 方法调用时传入的实际参数,先在栈空间分配,在方法调用完成后从栈空间释放。
- 字符串常量在 DATA区域分配,this在堆空间分配
- 数组既在栈空间分配数组名称,又在堆空间分配数组实际的大小
Java强引用,垃圾回收器绝不会回收它,即使内存不够报错。
Java引用分为四种级别:
- 强引用
- 软引用
- 弱引用
- 虚引用
1 | String abc = new String("abc"); //强引用 |
heap和stack区别
申请方式:
- stack是系统自动分配。系统自动在栈中开辟空间
- heap是程序员自己申请并且指定大小,通过new的方式
申请后系统反应:
- stack: 只要是栈的剩余空间大于所申请的空间大小,系统将为程序提供内存,否则包异常提示栈溢出
- heap: 操作系统有一个记录空间内存地址的链表,当系统收到程序申请时,会遍历链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从链表中删除,并把结点的空间分配程序。系统会将多余的那部分重新放入空闲链表中。
申请的大小限制:
- stack: 栈是向低地址扩展的数据结构,是一块连续的内存区域。栈顶地址和栈的最大容量是事先设定好的,栈的能获得空间很小
- heap:堆是从向高地址扩展的数据结构,不是连续的内存区域。由于系统是用链表来储存空间内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址的。堆的大小受限于计算机系统的有效虚拟内存的大小。由此可见,堆获得的空间比较灵活,也比较大。
申请效率的比较:
- stack: 由系统自动分配,速度较快。程序员无法控制的
- heap: 由new分配的内存,一般速度比较慢,容器产生内存碎片
Java的类加载器
种类
- 根类加载器
- 扩展类加载器
- 系统(应用)类加载器
- 自定义加载器(必须继承ClassLoader)
java类加载体系值ClassLoader双亲委托机制
java是一种类型安全的语言,它有四类称为安全沙箱机制的安全机制来保证语言的安全性,这四种分别是:
- 类加载机制
- .class文件检验器
- 内置于java虚拟机(及语言)的安全特性
- 安全管理器及java api
java程序中的.java文件编译完成会生成.class文件,而.class文件就是通过类加载器的ClassLoader加载的,而ClassLoader在加载过程中会使用“双亲委派机制”来加载.class文件