jvm(6)--string
String的基本特性
String:字符串,使用一对 ”” 引起来表示
String s1 = “mogublog” ; // 字面量的定义方式
String s2 = new String(“moxi”);
string声明为final的,不可被继承
String实现了Serializable接口:表示字符串是支持序列化的。实现了Comparable接口:表示string可以比较大小
string在jdk8及以前内部定义了final char[] value用于存储字符串数据。JDK9时改为byte[]
为什么JDK9改变了结构String类的当前实现将字符存储在char数组中,每个字符使用两个字节(16位)。从许多不同的应用程序收集的数据表明,字符串是堆使用的主要组成部分,而且,大多数字符串对象只包含拉丁字符。这些字符只需要一个字节的存储空间,因此这些字符串对象的内部char数组中有一半的空间将不会使用。String再也不用char[] 来存储了,改成了byte [] 加上编码标记,节约了一些空间
同时基于String的数据结构,例如StringBuffer和Strin ...
jvm(5)--内存
对象实例化
对象创建方式
new:最常见的方式、单例类中调用getInstance的静态类方法,xxxbulider/XXXFactory的静态方法
Class的newInstance方法:在JDK9里面被标记为过时的方法,因为只能调用空参构造器
Constructor的newInstance(XXX):反射的方式,可以调用空参的,或者带参的构造器 权限没有要求
使用clone():不调用任何的构造器,要求当前的类需要实现Cloneable接口中的clone接口
使用序列化:序列化一般用于Socket的网络传输
第三方库 Objenesis
创建对象的步骤判断对象对应的类是否加载、链接、初始化
首先去检查这个指令的参数能否在Metaspace的常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载,解析和初始化。(即判断类元信息是否存在)。如果没有,那么在双亲委派模式下,使用当前类加载器以ClassLoader + 包名 + 类名为key进行查找对应的 .class文件,如果没有找到文件,则抛出ClassNotFoundException异常,如果找到,则进行 ...
jvm(4)--方法区
栈、堆、方法区的交互关系
Person:存放在元空间,也可以说方法区
person:存放在Java栈的局部变量表中
new Person():存放在Java堆中
方法区《Java虚拟机规范》中明确说明:“尽管所有的方法区在逻辑上是属于堆的一部分,但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。”但对于HotSpotJVM而言,方法区还有一个别名叫做Non-Heap(非堆),目的就是要和堆分开。
所以,方法区看作是一块独立于Java堆的内存空间。
方法区主要存放的是 Class,而堆中主要存放的是 实例化的对象
方法区与Java堆一样,是各个线程共享的内存区域。
方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的。
方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。
方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误:jdk7 java.lang.OutofMemoryError:PermGen space 或者jdk8 java.lang.OutOfMemor ...
jvm(3)--堆
本地方法接口
一个Native Method就是一个java调用非java代码的接口,一个Native Method 是这样一个java方法:该方法的底层实现由非Java语言实现,比如C。这个特征并非java特有,很多其他的编程语言都有这一机制,比如在C++ 中,你可以用extern “C” 告知C++ 编译器去调用一个C的函数。在定义一个native method时,并不提供实现体(有些像定义一个Java interface),因为其实现体是由非java语言在外面实现的。本地接口的作用是融合不同的编程语言为java所用,它的初衷是融合C/C++程序。标识符native可以与其他所有的java标识符连用,但是abstract除外。
与java环境外交互:
与操作系统交互(比如线程最后要回归于操作系统线程)
Sun’s JavaSun的解释器是用C实现的,这使得它能像一些普通的C一样与外部交互。
本地方法栈1.Java虚拟机栈用于管理Java方法的调用,而本地方法栈用于管理本地方法(一般非Java实现的方法)的调用
2.本地方法栈,也是线程私有的。
3.允许被实现成固定或者是可动态 ...
jvm(2)--栈
运行时数据区内部结构
java虚拟机定了了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁。另外一些则是与县城一一对应的,这些与线程对应的数据区域会随着线程开始和结束而创建和销毁。如图,灰色的区域为单独线程私有的,红色的为多个线程共享的
1.每个线程:独立包括程序计数器、栈、本地栈
2.线程间共享:堆、堆外内存(方法区、永久代或元空间、代码缓存)
一般来说,jvm优化95%是优化堆区,5%优化的是方法区,至于栈区无非出入栈操作优化较少
每个Java应用程序都有一个Runtime类的实例,该实例允许该应用程序与运行该应用程序的环境进行交互。 当前运行时可以从getRuntime方法获得。
线程1.线程是一个程序里的运行单元,JVM允许一个程序有多个线程并行的执行;
2.在HotSpot JVM,每个线程都与操作系统的本地线程直接映射。
当一个java线程准备好执行以后,此时一个操作系统的本地线程也同时创建。java线程执行终止后。本地线程也会回收。
3.操作系统负责所有线程的安排调度到任何一个可用的CPU上。一旦本地线程初始化成 ...
多线程(4)
集合类不安全List 不安全
1234567891011121314151617181920212223// java.util.ConcurrentModificationException 并发修改异常!public class ListTest { public static void main(String[] args) { // 并发下 ArrayList 不安全的吗,Synchronized; /*** 解决方案; * 1、List<String> list = new Vector<>(); * 2、List<String> list = Collections.synchronizedList(new ArrayList<> ()); * 3、List<String> list = new CopyOnWriteArrayList<>(); */ // CopyOnWrite 写入 ...
多线程(3)
Lockreentrantlock使用reentrantlock可以完成sync的功能
CAS锁
需要注意的是,必须要必须要必须要手动释放锁(重要的事情说三遍)
使用syn锁定的话如果遇到异常,jvm会自动释放锁,但是lock必须手动释放锁,因此经常在finally中进行锁的释放
1234567891011121314151617181920212223242526272829303132333435public class T02_ReentrantLock2 { Lock lock = new ReentrantLock(); void m1() { try { lock.lock(); //synchronized(this) for (int i = 0; i < 10; i++) { TimeUnit.SECONDS.sleep(1); System.out.println(i); } } ...
多线程(2)
并发synchronized是可重入锁
synchronized是jdk提供的jvm层面的同步机制。它解决的是多线程之间访问共享资源的同步问题,它保证了在被它修饰的方法或代码块同一时间只有一个线程执行。
sync(Object) 不能实验String常量 Integer Long
java6之前的synchronized属于重量锁,性能较差,它是基于操作系统的Mutex Lock互斥量实现的。
因为java线程是映射到操作系统的线程之上的,所以暂停或唤醒线程都需要Java程序从用户态转换为内核态,这段转换时间消耗较长。
java6之后jvm团队对synchronized做出了非常大的优化。
synchronized底层原理先看我编写的一段测试代码:
使用 javap -c -v -l 指令反编译 class文件后的 字节码指令 如下
可以清楚的看到,在进入synchronized的时候,底层字节码编译出来的指令为monitorenter,在执行完同步代码块后又有一个monitorexit指令.
想了解synchronized究竟是如何实现的,可以直接进入openjdk:sr ...
GC
GC
判断对象存活的方法
引用计数法缺点
什么是GC Root ?
垃圾回收算法
复制算法(Copying)
标记-清除算法(Mark-Sweep)
标记-整理算法(Mark-Compact)
分代收集算法
内存分配与垃圾回收策略
一次GC的过程
动态年龄阈值
垃圾回收器
Serial串行收集器
Serial Old 串行收集器(老年代版本)
Parallel Scavenge 并行多线程收集器
Parallel Old 并行收集器(老年代版本)
ParNew 多线程收集器
CMS 并发标记清除收集器
CMS收集器回收过程
G1 收集器
G1回收器的特点
G1收集器回收过程
GC判断对象存活的方法在垃圾回收器对堆内存回收前,需要判断对象是否存活。
引用计数算法: 给每个对象添加一个引用计数器,每当对象被引用,对象的引用计数器就加1,当引用失效时,引用计数器就减1。直到引用计数器为0,就代表对象不再被引用。
可达性算法: 通过GC ROOT的对象节点往下搜索,节点走过的路径被称为引用链。如果一个对象不处于任何引用链,那么就可以判断此对象是不可达的。
引用计 ...
多线程
多线程进程和线程进程与线程最主要的区别是它们是操作系统管理资源的不同方式的体现。准确来说进程与线程属于衍生关系。进程是操作系统执行程序的一次过程,在这个过程中可能会产生多个线程。
比如在使用QQ时,有窗口线程,文字发送的线程,语音输入的线程,可能不是很恰当,但是就是这个意思。
由于系统在线程之间的切换比在进程之间的切换更高效率,所以线程也被成为轻量级进程。
并发和并行
并发: 多个程序可以同时运行的现象,更细化的是多进程可以同时运行或者多指令可以同时运行。多个线程任务被一个cpu轮流执行。并发强调的是计算机应用程序有处理多个任务的能力。并发的”同时”是经过上下文快速切换,使得看上去多个进程同时都在运行的现象,是一种OS欺骗用户的现象。
并行:多个线程被多个cpu同时执行。这里也并不是只允许多个cpu处理多任务,一个cpu也是可以的,只要cpu能在同一时刻处理多任务。并行的”同时”是同一时刻可以多个进程在运行(处于running)
并行强调的是计算机应用程序拥有同时处理多任务的能力。
并发和并行对比并发,指的是多个事情,在同一时间段内同时发生了。
并行,指的是多个事情 ...