java运行时数据区
Java内存区域(运行时数据区域)和内存模型(JMM)
Java 内存区域和内存模型是不一样的东西,内存区域是指 Jvm 运行时将数据分区域存储,强调对内存空间的划分。
而内存模型(Java Memory Model,简称 JMM )是定义了线程和主内存之间的抽象关系,即 JMM 定义了 JVM 在计算机内存(RAM)中的工作方式,如果我们要想深入了解Java并发编程,就要先理解好Java内存模型。
Java运行时数据区域(Runtime Data Area)众所周知,Java 虚拟机有自动内存管理机制,如果出现内存泄漏和溢出方面的问题,排查错误就必须要了解虚拟机是怎样使用内存的。
下图是 JDK8 之后的 JVM 内存布局。
程序计数器(Program Counter Register)程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。
由于 Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器内核都只会执行一条线程中的指令。
因此,为了线程 ...
硬件级别的缓存对程序的影响
硬件级别的缓存对程序的影响
JVM-合并写(write combining)
当cpu修改了某值后会把数据线存入L1中,这个时候可能没有命中,则会一往下查找,会写入到L2中,此时,由于往L2中写的时候需要大量的时间,同时这个变量还可能继续被修改,此时会用到合并写的技术,所谓合并写就是把两次的写的结果一次进行写出。这里会用到合并写的地址空间(WCBuffer),在64位的操作系统中一共4个字节,也就是如果我们的修改在4个字节以内,则会使用到合并写的技术,如果超过4个字节,则无法使用到合写的红利。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758final class WriteCombining { private static final int ITERATIONS = Integer.MAX_VALUE; private static final int ITEMS = 1 << 24; ...
对象定位的两种方式
对象定位的两种方式 由于reference类型在Java虚拟机规范里只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位,以及访问到Java堆中的对象的具体位置,因此不同虚拟机实现的对象访问方式会有所不同,主流的访问方式有两种:使用句柄和直接指针。
1、使用句柄访问方式
如果使用句柄访问方式,Java堆中会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息。使用句柄方式最大的好处就是reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要被修改。
二、使用直接指针访问方式
如果使用该方式,Java堆对象的布局就必须考虑如何放置访问类型数据的相关信息,reference中直接存储的就是对象地址。使用直接指针方式最大的好处就是速度更快,他节省了一次指针定位的时间开销。
就HotSpot而言,他使用的是直接指针访问方式进行对象访问,但从整个软件开发的范围来看,各种语言和框架使用句柄来访问的情况也 ...
使用JavaAgent观察new对象占的的内存的大小
new Object()占的的内存的大小JavaAgent 介绍
以前在做后台服务开发的时候,SpringBoot每次改动代码都需要手动重启才能生效,感觉贼麻烦,后来使用Spring提供的一款热部署插件,它只是部分重启,相当于重新加载了我们自己写的代码,效率提高很多。后来遇到了Jrebel,它只重新加载我们修改的那个类,比Springboot热部署插件重启速度更快,连改mybatis的xml文件都能热部署,太方便了有不有!(顺便安利一下同一家公司的另一个软件XRebel,实时监控服务请求)后来又接触了BTrace,它可以线上调试代码而不需要重启项目,也是很吊的一个东西。通过了解,上面所说的几个东西都是通过Java Agent来实现的,那么Java Agent到底是啥,为啥这么吊?
在JDK1.5以后,我们可以使用agent技术构建一个独立于应用程序的代理程序(即为Agent),用来协助监测、运行甚至替换其他JVM上的程序。使用它可以实现虚拟机级别的AOP功能。
Agent分为两种,一种是在主程序之前运行的Agent,一种是在主程序之后运行的Agent(前者的升级版,1.6以后提供),这 ...
Java 类的加载过程
Java 类的加载过程1.Loading 使用双亲委派机制将 .class加载到内存中
为什么要使用双亲委派
防止加载同一个.class。通过委托去询问上级是否已经加载过该.class,如果加载过了,则不需要重新加载。保证了数据安全。
保证核心.class不被篡改。通过委托的方式,保证核心.class不被篡改,即使被篡改也不会被加载,即使被加载也不会是同一个class对象,因为不同的加载器加载同一个.class也不是同一个Class对象。这样则保证了Class的执行安全。
自定义类加载器 加密代码
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556public class ClassLoaderWithEncription extends ClassLoader { public static int seed = 0B10110110; @Override protected Class&l ...
GC的基础知识
GC和GC Tuning1.什么是垃圾
没有任何引用指向的一个对象或者多个对象(循环引用)
2.如何定位垃圾
引用计数(ReferenceCount)
根可达算法(RootSearching)
3. GC roots
JVM stack (jvm栈)
native method stack (本地方法栈)
run-time constant pool (常量池指向的变量)
static references in method artea (静态变量指向的对象)
Clazz (对象字节load到内存)
3.常见的垃圾回收算法
标记清除(mark sweep) - 位置不连续 产生碎片 效率偏低(两遍扫描)
拷贝算法 (copying) - 没有碎片,浪费空间
标记压缩(mark compact) - 没有碎片,效率偏低(两遍扫描,指针需要调整)
4.JVM内存分代模型(用于分代垃圾回收算法)1. 部分垃圾回收器使用的模型
除Epsilon ZGC Shenandoah之外的GC都是使用逻辑分代模型
G1是逻辑分代,物理不分代
除此之外不仅逻辑分代,而且物理分代
2. 新 ...
代码的精简之道
前言古语有云:
道为术之灵,术为道之体;以道统术,以术得道。
其中:“道”指“规律、道理、理论”,“术”指“方法、技巧、技术”。意思是:“道”是“术”的灵魂,“术”是“道”的肉体;可以用“道”来统管“术”,也可以从“术”中获得“道”。
在拜读大佬“孤尽”的文章《Code Review是苦涩但有意思的修行》时,感受最深的一句话就是:“优质的代码一定是少即是多的精兵原则”,这就是大佬的代码精简之“道”。
工匠追求“术”到极致,其实就是在寻“道”,且离悟“道”也就不远了,亦或是已经得道,这就是“工匠精神”——一种追求“以术得道”的精神。如果一个工匠只满足于“术”,不能追求“术”到极致去悟“道”,那只是一个靠“术”养家糊口的工匠而已。作者根据多年来的实践探索,总结了大量的 Java 代码精简之“术”,试图阐述出心中的 Java 代码精简之“道”。
1.利用语法1.1.利用三元表达式普通:
123456String title;if (isMember(phone)) { title = "会员";} else { title = ...
NIO
NIO1. NIO是什么
NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的有效方式。
2.常见I/O模型对比
所有的系统I/O都分为两个阶段:等待就绪和操作。举例来说,读函数,分为等待系统可读和真正的读;同理,写函数分为等待网卡可以写和真正的写。
需要说明的是等待就绪的阻塞是不使用CPU的,是在“空等”;而真正的读写操作的阻塞是使用CPU的,真正在”干活”,而且这个过程非常快,属于memory copy,带宽通常在1GB/s级别以上,可以理解为基本不耗时。
传统的BIO里面socket.read(),如果TCP RecvBuffer里没有数据,函数会一直阻塞,直到收到数据,返回读到的数据。
对于NIO,如果TCP RecvBuffer有数据,就把数据从网卡读到内存,并且返回给用户;反之则直接返回0,永远不会阻塞。
最新的AIO(Async I/O)里面会更进一步:不但等待就绪是非阻塞的,就连数据从网卡到内存的过 ...
java中基于文件的NIO
java 中文件NIO1. 内存映射文件
通俗点,就是ReadFile和WriteFile这样的I/O系统函数, 在文件里来回地读、写、移动文件指针效率低 速度慢;CreateFileMapping函数允许应用程序把文件映射到一个进程,这样文件内的数据就可以用内存读/写指令来访问,提高效率。
再通俗点,就是比如 要读取一个文件里的东西 这时候你就得去硬盘读,但是映射到内存后 就可以直接对这块内存操作了;写操作也一个意思。。。。。就是把要在硬盘上搞的东西 弄到内存搞 搞起来方便
JDK1.4版本引入了java.nio包,对文件流进行读写操作,提供无阻塞模式,同时也提供了一种高效率的文件读写模式,内存映射文件,把文件某个区域块映射到内存,进行高效率的读写,主要用到下面类java.nio.MappedByteBuffer;java.nio.channels.FileChannel
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 ...
BIO
BIO1. 什么是BIO
B I/O,意为Blocking I/O,即阻塞的I/O。
很明显重点在阻塞,但怎么就阻塞了?阻塞在哪了?阻塞带来了什么坏处?
2. BIO的代码实现:
服务端
1234567891011121314151617181920212223242526272829303132333435public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(9090,20); System.out.println("step1: new ServerSocket(9090) "); while (true) { Socket client = server.accept(); //阻塞1 System.out.println("step2:client\t" + client.getPort()); new Thre ...