Java对象
一个对象在可以被使用之前必须被正确地初始化,实例化,对象是如何创建,由什么组成,又是放在JVM的哪个地方,以及如何使用对象。
创建对象的方式
使用new关键字创建,这是最常见的一种方式,可以调用任意的构造函数来创建1Person p = new Person();
使用Class类的newInstance方法,只能调用空参构造器123//获取类对象Class aClass = Class.forName("priv.starfish.Person");Person p1 = (Person) aClass.newInstance();
Constructor的 newInstance(xxx),对构造器没有要求1234Class aClass = Class.forName("priv.starfish.Person");//获取构造器Constructor constructor = aClass.getConstructor();Person p2 = (Person) constructor.newInstance();
使用clone ...
几种引用的区别
Java中的引用类似C++中的指针,用来指向一个对象,指向对象的变量叫做引用变量,除了8中基本类型,其他的类型都是引用类型,主要包括:类、接口、数组、枚举、注解。
主要分为四种引用:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference),引用强度依次减弱,生命周期也不一样。JVM的垃圾回收机制分别进行不同的处理。
强引用最常见的一种引用,是将一个对象赋值给另一个引用变量,这个引用变量就是强引用,当一个对象被强引用变量引用时,一直是可到达状态,GC是不能回收的,因此也是导致内存泄漏的常见原因之一,比如:
1234567Object obj1 = new Object();// 强引用Object obj2 = obj1;obj1=null;System.gc();System.out.println("对象1:"+obj1);System.out.println("对象2:"+obj2);
软引用如果一个对象只具有软引用,那就 ...
Java性能调优
如何根据项目的需要设置Java运行参数,以达到更好的运行效率,及出现性能瓶颈时如何优化,还有哪些潜在的经验和规则。
JVM调优
GC的性能指标主要考虑两个方面:吞吐量和STW时间。应尽量减少Major GC的频率。
堆大小尽量设置大一点,且-Xms和-Xmx设置相同的大小;
新生代大小设置合理,通过-Xmn参数设置,控制好新生代和老年代的比例,如果过小,则会导致频繁YGC,对象进入老年代,使老年代过早进入FullGC;
当使用CMS收集器的时候,老年代会产生内存碎片,因此要开启-XX:+UseCMSCompactAtFullCollection参数来开启对老年代内存的压缩,使用-XX:CMSFullGCsBeforeCompaction=0参数,进行多少次FullGC后压缩;
采用并发回收时,年轻代可以小一点,年老代要大,因为年老代用的是并发回收,即使时间长点也不会影响其他程序继续运行,网站不会停顿;
如果是web应用,采用CMS收集器时,可能是好的选择。
常见的OOM异常
在《Java虚拟机规范》的规定里,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError 异常的可能,本章主要介绍相关的OOM异常。
概述常见的OOM异常为:
StackOverflowError堆栈溢出,一种常见的递归调用过深引起的异常。
Java heap space最常见的异常。
GC overhead limit exceededGC回收的耗时过长,且频繁。
Direct buffer memory本地直接内存溢出。
unable to create new native thread无法创建更多线程。
Metaspace方法区溢出。
Requested array size exceeds VM limit创建的数组超过的JVM最大长度限制。
Out of swap space
Kill process or sacrifice child操作系统层面的。
堆栈溢出比较常见的是一些需要递归调用的时候,由于每次函数调用会在当前线程生成一个栈帧,当调用过深的时候,导致栈溢出。如常见的斐波那契数列的计算,如果不判断初始条件,则很容易出现这 ...
垃圾回收实战
接下来根据详细的栗子,说明GC日志的查看,JVM参数的调整。
JVM参数配置工作中常用的JVM参数配置,及如何调优。
JVM参数类型
标准参数(-),JVM各个版本基本保持不变,相对稳定且向后兼容;
非标准参数(-X),变化较小的参数,默认JVM实现参数,且不保证向后兼容;
非Stable参数(-XX),各个JVM的实现不同,将来可能会取消。
标准参数标准参数可以输入java查看:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950用法: java [-options] class [args...] (执行类) 或 java [-options] -jar jarfile [args...] (执行 jar 文件)其中选项包括: -d32 使用 32 位数据模型 (如果可用) -d64 使用 64 位数据模型 (如果可用) -server ...
垃圾回收
Java相比C/C++的一个显著特点就是自动管理内存,不用程序员关心内存的释放,当Java程序也出现OOM异常的时候,不禁让人摸不着头脑,Java是如何实现对内存的管理的?主要是JVM实现的垃圾回收机制(Garbage collection),判断堆中的对象实例或者数据是否是垃圾,是垃圾就定时清理掉。
如何识别垃圾引用计数法简单来说,就是对象被引用一次,则在对象头上加一个引用计数增1,不在使用时减1,当引用计数变为0的时候,则认为可以回收。主要的问题,无法解决循环引用,就是A类中一个属性引用了B类对象,B类中一个属性引用了A类对象,这样一来,就算你把A类和B类的实例对象引用置为null,它们还是不会被回收;
可达性分析法核心思想为 : 通过一系列称为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称之为引用链,当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的。
可作为GC Roots的对象有以下几种:
虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的 ...
JVM内存结构
Java 虚拟机定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁。另外一些则是与线程对应,这些与线程对应的数据区域会随着线程开始和结束而创建和销毁。
线程私有的:程序计数器、栈、本地方法栈;
线程共享的:堆、方法区(永久代或元空间、代码缓存)。
程序计数器程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。如一段程序:
123456 public static void main(String[] args) { int i=10; int j=23; int sum = i+j; System.out.println(sum);}
在idea上使用jclasslib反编译查看字节码为:
注意:
是一块很小的存储空间,运行速度也最快;
在JVM规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期一致;
任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。如果当前线程正在执行的是 Java 方法,程序计数器记录的 ...
JVM是什么
我们都知道Java程序与其他面向对象语言(C++)的主要区别是一次编译跨平台运行,自动内存管理,自动垃圾回收等功能。这些功能都得益于Java提供的一种叫做JVM的东西,JVM到底是什么,为什么能做到,下文进行详细描述。
JVM是什么JVM是Java Virtual Machine的缩写,即Java虚拟机,一说起虚拟机,我们首先会想到的是诸如VMware、VisualBox等虚拟机软件,用于创建隔离主机系统的子系统。同样,JVM也是根据一定的规范,来虚构出来的一个子系统用来运行Java字节码,各个平台实现自己的虚拟机,因此,针对同一份Java字节码,可以做到不同的平台都能运行,因为JVM隔离了Java程序与底层的直接操作,将字节码解释编译成对应平台的机器指令执行。注:规范中规定了Java字节码的二进制文件格式,及各种Java指令的作用。
JVM整体结构如下图:图片来源:JavaKeeper
类加载子系统
类加载子系统负责把二进制字节码(Class文件)装载到内存,并对数据进行校验、转换解析、初始化,最终生成被虚拟机直接使用的Java类型。
类加载子系统的作用类加载子系统的组成:
作用:
类加载子系统负责从文件系统或者网络中加载 class 文件,class 文件在文件开头有特定的文件标识(0xCAFEBABE)
ClassLoader 只负责 class 文件的加载。至于它是否可以运行,则由 Execution Engine 决定
加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是class文件中常量池部分的内存映射)
Class 对象是存放在堆区的。
类加载过程类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。(验证、准备和解析又统称为连接,为了支持 Java 语言的运行时绑定,所以解析阶段也可以是在初始化之后进行的。以上顺序都只是说开始的顺序,实际过程中是交叉的混合式进行的,加载过程中可能就已经开始验证了)
1 ...
mybatis自定义TypeHandler
PostgreSQL中提供了json数据类型,并支持常用的关系数据库的查询语法,在实际的工作中,存储复杂的数据带来一些便利,数据持久层的框架使用Mybatis进行处理的时候,需要单独处理Json类型的字段。在高版本的Mybatis Plus中已经对此支持了。以下纪录自定义类型处理函数来处理特定的字段类型。
自定义处理函数继承Mybatis中的BaseTypeHandler,重写其中的几个方法,使用fastjson作为json字段的序列化和反序列化工具。
1234567891011121314151617181920212223242526@MappedTypes({Object.class})public class JsonTypeHandler extends BaseTypeHandler<Object> { @Override public void setNonNullParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdb ...