4. JVM内存管理(附:建立一个对象的过程)
内存空间JVM 逻辑内存模型图
内存空间主要包含:
程序计数器
方法区
运行时常量池
堆
新生代
老生代
栈
局部变量表
操作数栈
指向运行时常量池的地址
方法返回地址
附加信息
本地方法栈
整体图解
运行时数据区
线程共享与私有模型图解
程序计数器程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
由于Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
如果线程正 ...
4. 内存回收(Client、Server模式)
JVM有两种运行模式Server与Client。两种模式的区别在于:
Client模式启动速度较快
Server模式启动较慢
但是启动进入稳定期长期运行之后Server模式的程序运行速度比Client要快很多。这是因为:
Server模式启动的JVM采用的是重量级的虚拟机,对程序采用了更多的优化;
Client模式启动的JVM采用的是轻量级的虚拟机。所以Server启动慢,但稳定后速度比Client远远要快。
1. 当前是Client or Server?使用Java -version命令就能显示出当前虚拟机处于哪种模式。
Client
Server另外我们也能看到该虚拟机是64位的。如果像上面的Client图中那样不显示位数,则是32位虚拟机。所以使用java -version也能查看虚拟机是32位还是64位。
2. Client与Server切换
2.1 模式切换如果要切换启动模式,首先要确认JDK支持哪一种或两种模式。查看JAVA_HOME/jre/bin目录下是否存在client或server目录。
32位的JDK一般都支持server ...
4. 内存消耗分析
对JVM内存的分析,第四章已有介绍,对JVM以外的内存消耗,最为值得关注的是SWAP的消耗以及物理内存的消耗,这两方面的消耗都可基于OS的命令来查看。
vmstat在命令行中输入vmstat,输出信息和内存相关的主要是:
memory下
swpd
free
buff
cache
swap下
si
so
参数
意义
swpd
指虚拟内存中已使用的部分(kb)
free
指空闲物理内存
cache
表示用于缓存的内存
swap下的si
指每秒从disk读至内存的数据量
swap下的so
指每秒从内存写入disk的数据量
swpd过高通常是物理内存不够用,os将物理内存中的一部分数据转为放入硬盘上进行存储,以腾出足够的空间供程序使用。
在目前运行的程序变化后,即从硬盘重新读取到内存中,以便恢复程序的运行,这个过程会产生swap IO,因此查看swap消耗情况主要关注的就是swap IO的状况
对于JAVA应用,属于单进程应用,因此只要JVM不是设置的过大,不会操作到swap区域。物理内存消耗过多,可能是
JVM设置过大
创建的JAVA线程太 ...
4. 实现⼀个分页插件
数据库分页插件
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748@Intercepts({ @Signature( type = Executor.class, // 目标类 method = "query", // 目标方法 args ={MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class} )})public class MySqlPagingPlugin implements Interceptor { private static final Integer MAPPED_STATEMENT_INDEX = 0; private static final Integer PARAMETER_INDE ...
4. BlockingCache
BlockingCache 实现了阻塞特性,该特性是基于Java重入锁实现的。同一时刻下,BlockingCache 仅允许一个线程访问指定 key 的缓存项,其他线程将会被阻塞住。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576public class BlockingCache implements Cache { private long timeout; private final Cache delegate; private final ConcurrentHashMap<Object, ReentrantLock> locks; public BlockingCache(Cache delegate) { this.delegate = delegate ...
4. 创建 StatementHandler
在 MyBatis 的源码中,StatementHandler 是一个非常核心接口。之所以说它核心,是因为从代码分层的角度来说,StatementHandler 是 MyBatis 源码的边界,再往下层就是 JDBC 层面的接口了。
StatementHandler 需要和 JDBC 层面的接口打交道,它要做的事情有很多。在执行 SQL 之前,StatementHandler 需要创建合适的 Statement 对象,然后填充参数值到Statement 对象中,最后通过 Statement 对象执行 SQL。 SQL 执行完毕,还要去处理查询结果等。
StatementHandler 的继承体系最下层的三种 StatementHandler实现类与三种不同的Statement进行交互,这个不难看出来。但 RoutingStatementHandler 则是一个奇怪的存在,因为JDBC中并不存在RoutingStatement。
12345678910111213// -☆- Configurationpublic StatementHandler newStatementHand ...
4. 解析cache-ref节点
在 MyBatis 中,二级缓存是可以共用的。这需要通过节点为命名空间配置参照缓存,比如像下面这样。
1234567891011<!-- Mapper1.xml --><mapper namespace="xyz.coolblog.dao.Mapper1"> <!-- Mapper1 与 Mapper2 共用一个二级缓存 --> <cache-ref namespace="xyz.coolblog.dao.Mapper2"/></mapper><!-- Mapper2.xml --><mapper namespace="xyz.coolblog.dao.Mapper2"> <cache/></mapper>
配置分析 cache-ref 的解析过程
1234567891011121314151617private void cacheRefElement(XNode context) { ...
4. volatile的内存语义
当声明共享变量为volatile后,对这个变量的读/写将会很特别。为了揭开volatile的神秘面纱,下面将介绍volatile的内存语义及volatile内存语义的实现。
volatile的特性理解volatile特性的一个好方法是把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步。
12345678910111213class VolatileFeaturesExample { volatile long vl = 0L; // 使用volatile声明64位的long型变量 public void set(long l) { vl = l; // 单个volatile变量的写 } public void getAndIncrement () { vl++; // 复合(多���)volatile变量的读/写 } public long get() { return v ...
4. 返回结果的 HTTP 状态码
状态码告知从服务器端返回的请求结果状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误
状态码以 3 位数字和原因短语组成,数字中的第一位指定了响应类别,后两位无分类。
类别
原因短语
1XX
Informational(信息性状态码)
接收的请求正在处理
2XX
Success(成功状态码)
请求正常处理完毕
3XX
Redirection(重定向状态码)
需要进行附加操作以完成请求
4XX
Client Error(客户端错误状态码)
服务器无法处理请求
5XX
Server Error(服务器错误状态码)
服务器处理请求出错
只要遵守状态码类别的定义,即使改变RFC2616中定义的状态码,或服务器端自行创建状态码都没问题。
上经 常使用的大概只有 14 种。
2XX 成功2XX 的响应结果表明请求被正常处理了。
200 OK在响应报文内,随状态码一起返回的信息会因方法的不同而发生改变。
使用 GET 方法时,对应请求资源的实体会作为响应返 回
使用 HEAD ...