比较多的东西,写的比较杂乱,以后会写一些自己复习到的内容,或者新学习到的东西,尽量让自己写的东西有价值,对一天学习的内容有一个总结。
一、Classloader
1、过程
1)加载:查找并加载类的二进制数据。
将.class文件中的二进制数据读入到内存,将其放在运行时数据的方法区,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
非本地加载.class文件 urlclassloader
当加载完成之后,就进入连接阶段,连接阶段就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中
2)连接:
验证:确保被加载的类的正确性
准备:为类的静态变量分配内存,并初始化为默认值
当我的类中有静态变量时,eg:static int i = 6 ,会在这个阶段,为其分配内存4个字节,并初始化默认值0
解析:把类中的符号引用转换为直接引用。
在解析阶段,jvm会把类的二进制数据中的符号引用替换为直接引用
假设有个AAA类里面的aaa方法调用XXX类中bbb方法
public void aaa(){
xxx.bbb(); //该调用在AAA的二进制中标示为符号引用
}
JVM将把这个符号引用替换为一个指针,指向XXX的bbb方法区的内存地址,该指针就是直接引用
3)初始化:为类的静态变量赋正确的初始值 int = 6
2、加载器
根类加载器Bootstrap native(c语言)实现
扩展类加载器Extension java实现
系统类加载器(也叫应用类加载器)System java实现
Bootstrap在整个程序开始启动的时候,会直接加载jdk下的lib文件下的类,Extension会加载jre下的lib下ext下的类,System会加载classpath下的类(包括在工程中lib下的第三方jar包,自己写的classloader),前面两个类加载器在启动的时候会将所有的类全部加载完毕,而后一个动态加载所需类,以下五种情况会加载类:
创建类实例 new Test()
访问类或接口静态变量以及赋值 int b=Test.a Test.a=b
调用静态方法 Test.do()
反射调用 class.forname
初始化子类 class P class T extend P T.xxx
java虚拟机启动时标示为启动类的类 meta-inf
3、类的委托机制
二、NIO ByteBuffer.allocateDirect的回收
ByteBuffer bd = ByteBuffer.allocateDirect(30); ((DirectBuffer)bd).cleaner().clean();
ByteBuffer可以申请直接内存,但是很能做到主动回收,System.gc()只是向虚拟机通知该做一次fullgc,但是几时做,做没做不知道。((DirectBuffer)bd).cleaner().clean()可以做到回收,将你在堆外的对象进行一次强制类型转换,将其转化成一个堆内对象,”欺骗“虚拟机,这样就可以对堆外内存进行回收。
三、一致性Hash
这个就是一个小的demo,hashutil不是自己写的,整个demo用来表现一致性hash的一种思想
public class ConsistentHash { public static HashMap<Integer,String> hashMap = new HashMap(); public static void dealNode(){ HashUtil hash = new HashUtil(); String realip1 = "172.16.204.112"; String realip2 = "172.16.204.129"; String realip3 = "172.16.204.104"; int node1 = hash.Hash(realip1); int node2 = hash.Hash(realip2); int node3 = hash.Hash(realip3); hashMap.put(node1,realip1); hashMap.put(node2,realip2); hashMap.put(node3,realip3); putNode(node1,realip1); putNode(node1,realip2); putNode(node1,realip3); System.out.println("对真实节点ip处理完成......"); System.out.println("开始布置虚拟节点......"); } public static HashMap putNode(int node,String ip){ for(int i = node;i<=65535;i=i+1000){ hashMap.put(node,ip); } for(int i = node;i>=0;i=i-1000){ hashMap.put(node,ip); } System.out.println("虚拟节点完成"); return hashMap; } public static void virtualNode(){ System.out.println("对到来的数据包进行分析......"); String ip = "198.126.23.132"; System.out.println("对数据来源IP进行Hash. . . . . ."); HashUtil hashUtil = new HashUtil(); int node = hashUtil.Hash(ip); while(hashMap.get(node)==null){ node++; } System.out.println("将数据发送给真实ip:"+ hashMap.get(node)); } public static void main(String[] args) { dealNode(); virtualNode(); } }
public class HashUtil { public static int Hash(String s) { char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5' }; try { byte[] btInput = s.getBytes(); // 获得MD5摘要算法的 MessageDigest 对象 MessageDigest mdInst = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 mdInst.update(btInput); // 获得密文 byte[] md = mdInst.digest(); // 把密文转换成十六进制的字符串形式 int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return Integer.parseInt(new String(str).substring(0, 8)); } catch (Exception e) { e.printStackTrace(); return 0; } } }
四、一些其他的内容
public class ObjectTest implements Serializable { public String name ="oooooooooo"; }
public class Test { public static void main(String[] args) { ObjectTest objectText = new ObjectTest(); System.out.println(objectText.toString()); } }
当一个对象,没有序列化之前,在堆是一块一块的存放的(有点像hdfs存放文件)。序列化以后,在堆中划一块连续内存存放对象,当拿出来时也是一块的连续的内存。