一、在JDK1.6(HotSpot虚拟机)及以前,运行时常量池(属于方法区的一部分)是永久代的,而在JDK1.7以后运行时常量池(里面用于存放编译期生成的各类字面量和符号引用,这部份内容将在类加载后进入方法区的运行时常量池当中存放)已经从永久代(Permanent Generation)移出。(问:那么方法区其余部分有没有移出永久代?)java
二、关于String.intern()方法,在1.6及之前会把首次遇到的字符串实例复制到永久代当中去,返回的也是永久代中这个字符串实例的引用;在1.7以后intern()实现不会再复制实例,只是在常量池中记录首次出现的实例引用,返回的就是那个实例引用。算法
三、Java的JVM并非经过引用计数来进行GC,由于它很难解决对象之间相互循环引用的问题,譬如:安全
public class Test{ public Object instance = null; public static void testGC(){ Test objA = new Test(); Test objB = new Test(); objA.instance = objB; objB.instance = objA; objA=null; objB=null; //假设在这行发生了GC,objA 和 objB可否被回收? System.gc(); } }
虽然这两个对象都已经不可能再被访问了,可是因为他们相互引用这对方,致使它们的引用计数都不为0,因而引用计数算法没法通知GC收集器回收它们。并发
四、Java采用可达性分析来判断对象是否存活,通常经过”GC ROOTS“的对象来做为起始点,通常可做为“GC roots”的对象包括下面4种:优化
1)虚拟机栈(栈帧中的本地变量表)中引用的对象。spa
2)方法区中类静态属性引用的对象。线程
3)方法区中常量引用的对象。code
4)本地方法栈中JNI(即通常说的Native方法)引用的对象。对象
五、JDK1.2以后Java对引用的概念进行了扩充,分为四种,引用强度依次从强到弱为强引用>软引用>弱引用>虚引用blog
强引用是普通的相似 Object obj = new Object()的对象引用
软引用(经过SoftReference类来实现)用来描述一些还有用但不是必须的对象,当发生内存溢出异常以前,将会把这一类对象列入回收范围之中进行第二次回收,若是此次回收以后仍是不够,就报内存溢出异常。
弱引用(WeakReference类来实现)也是用来描述非必须对象,但它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生以前
虚引用(PhantomReference)最弱的一种引用关系,没法经过虚引用来取得一个对象实例,通常为对象设置虚引用关联的惟一目的就是能在这个对象被收集器回收的时候收到一个系统通知。
六、Class文件当中的一些数据项目:
常量池容量计数值(constant_pool_count),用于表示常量池中常量的数值。须要注意的是这里容量计数是从1开始的,由于0有特别用途,好比0x0016表示十进制的22,这就表明常量池中有21项常量,索引范围为1~21.
常量池中主要存放两大类常量:字面量(如文本字符串,声明为final的常量值) 和 符号引用 (属于编译原理方面的概念,包括三类常量 见P168)
七、类从被加载到虚拟机内存到卸载出内存为止,整个生命周期包括哪些阶段?
一共包括7个阶段。加载->验证->准备->解析->初始化->使用->卸载。其中验证、准备、解析3个部分统称为链接。
须要注意的是,加载(Loading)是类加载(Class Loading)过程的一个阶段,别混淆了两个概念。类加载过程包括上述的前5个过程。
验证阶段大体上会完成4个阶段的验证动做:文件格式验证、元数据验证、字节码验证、符号引用验证。
八、使用volatile修饰的变量在并发下的运算必定是安全的吗?
因为java里面的运算并不是原子操做,致使volatile变量的运算在并发下同样是不安全的。因为volatile变量只能保证可见性,因此只有知足如下两条规则的运算场景才能够不用锁就能保证原子性。
1)运算结果并不依赖变量的当前值,或者可以确保只有单一的线程修改变量的值。
2)变量不须要与其余的状态变量共同参与不变约束。
volatile的可见性是经过Java内存模型对volatile变量定义的特殊规则,每次使用前都要read、load,每次用完都要store、write相关联,必须连续一块儿出现。
九、线程的实现通常有三种:内核线程实现(包括高级接口——轻量级进程)、用户线程实现、用户线程实现加轻量级进程混合实现
内核线程实现优势:即便有一个轻量级进程在系统调用中阻塞了,也不会影响整个进程继续工做
缺点:系统调用代价比较高,须要在两种态当中来回切换,因为每一个LWP都须要一个内核线程的支持,所以会消耗内核资源,支持的数量有限。
用户线程实现优势:操做快,消耗少,支持规模更大的线程数量
缺点:阻塞问题如何处理,多处理器系统中如何将线程映射到其余处理器上,这类问题解决起来异常困难
混合实现:
十、线程调度方式主要分为两种:协同式和抢占式。
十一、自旋锁(JVM层面的锁优化技术):在许多应用上,共享数据的锁定状态只会持续很短的一段时间,为了这段时间去挂起和恢复线程并不值得,因此若是物理机器有一个以上的处理器,能让两个或以上的线程同时并行执行,咱们就可让后面请求所的那个线程“稍等一下”,看看持有锁的线程是否很快就释放锁,这种让线程采用忙循环(自旋),这项技术就是所谓的自旋锁。
优势:避免线程切换的开销(内核态与用户态的上下文切换)
缺点:占用处理器的时间,对处理器数量有要求。
十二、Java语言定义的GC Roots对象包括:
1)虚拟机栈(栈帧中的本地变量表)中引用的对象。
2)方法区中静态属性引用的对象
3)方法区中常量引用的对象
4)本地方法栈中JNI引用的对象