Netty

Netty

What is Netty?

Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.

image-20200721113424540

Unix 提供的5种I/O模型:

  • 阻塞I/O模型:
  • 非阻塞I/O模型:
  • I/O复用模型:
  • 信号驱动模型:
  • 异步I/O:

NIO服务端时序图

1
2
3
4
5
6
7
8
9
10
11
NioServer->NioServer: 1.打开ServerSocketChannel
NioServer->NioServer: 2.绑定监听地址InetSocketAddress
Reactor Thread->Reactor Thread: 3.创建Selector,启动线程
NioServer->Reactor Thread: 4.将ServerSocketChannel注册到Selector,监听SelectionKey.OP_ACCEPT
Reactor Thread->Reactor Thread:5.Selector轮询就绪的Key
IoHandler->Reactor Thread: 6.handlerAccept()处理新的客户端接入
IoHandler->IoHandler: 7.设置新客户端连接的Socket参数
IoHandler->Reactor Thread:8.向Selector注册监听读操作SelectionKey.OP_READ
Reactor Thread->IoHandler: 9.handleRead()异步读消息到ByteBuffer
IoHandler->IoHandler: 10.decode请求消息
IoHandler->Reactor Thread: 11.异步写ByteBuffer到SocketChannel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//第一步:打开ServerSocketChannel,用于监听客户端的连接,它是所有客户端的父管道
ServerSocketChannel acceptorSvr = ServerSocketChannel.open();
//第二步,绑定监听端口,设置连接为非阻塞模式
acceptorSvr.socket().bind(new InetSocketAddress(InetAddress.getByName("IP"),port));
acceptorSvr.configureBlocking(false);
//第三步,创建Reactor线程,创建多路复用器并启动线程
Selector selector = Selector.open();
New Thread(new ReactorTask()).start();
//第四步,将ServerSocketChannel注册到Reactor线程的多路复用器Selector上,监听ACCEPT事件
SelectionKey key = acceptorSvr.register(selector,SelectionKey.OP_ACCEPt,ioHandler);
//第五步,多路复用器在线程run方法的无限循环体内轮询准备就绪的key
int num = selector.select();
Set selectedKeys = selector.selectedKeys();
Iterator it = selectedKeys.iterator();
while(it.hasNext()){
SelectionKey key = (SelectionKey)it.next();
// ... deal with I/O event ...
}
//第六步,多路复用器监听到有新的客户端接入,处理新的接入请求,完成TCP三次握手,建立物理链路
SocketChannel channel = svrChannel.accept();
//第七步,设置客户端链路为非阻塞模式
channel.configureBlocking(false);
channel.socket().setReuseAddress(true);
//第八步,将新接入的客户端连接注册到Reactor线程的多路复用器上,监听读操作,用来读取客户端发送的网络消息
SelectionKey key = socketChannel.register(selector,SelectionKey.OP_READ,ioHandler);
//第九步,异步读取客户端请求消息到缓冲区
int readNumber = channel.read(receivedBuffer);
//第十步,对ByteBuffer进行编码,如果有半包消息指针reset,继续读取后续的报文,将解码成功的消息封装成Task,投递到业务线程池中,进行业务逻辑编排
Object message = null;
while(buffer.hasRemain()){
byteBuffer.mark();
Object message = decode(byteBuffer);
if(message == null){
byteBuffer.reset();
break;
}
messageList.add(message);
}
if(!byteBuffer.hasRemain()){
byteBuffer.clear();
}else{
byteBuffer.compact();
}
if(messageList !=null &!messageList.isEmpty()){
for(Object messageE : messageList){
handlerTask(messageE);
}
}
//第十一步,将POJO对象encode成ByteBuffer,调用SocketChannel的异步write接口,将消息异步发送给客户端
socketChannel.write(buffer);

NIO客户端时序图

1
2
3
4
5
6
7
8
9
10
11
12
13
NioClient->NioClient:1.打开SocketChannel
NioClient->NioClient:2.设置SocketChannel为非阻塞模式,同时设置TCP参数
NioClient->server:3.异步连接服务端
NioClient->NioClient:4.判断连接结果,如果连接成功,调到步骤10,否则执行步骤5
NioClient->Reactor Thread:5.向Reactor线程的多路复用器注册OP CONNECT事件
Reactor Thread->Reactor Thread:6.创建Selector,启动线程
Reactor Thread->Reactor Thread:7.Selector轮询就绪的Key
Reactor Thread->IoHandler:8.handerConnect()
IoHandler->IoHandler:9.判断连接是否完成,完成执行步骤10
IoHandler->Reactor Thread:10.向多路复用器注册读事件OP_READ
Reactor Thread->IoHandler:11.handleRead()异步读请求消息到ByteBuffer
IoHandler->IoHandler:12.decode请求消息
IoHandler->Reactor Thread:13.异步写ByteBuffer到SocketChannel

mac按键符号

mac按键符号

符号 说明
⌘ Command
⇧ Shift
⌥ Option
⌃ Control
↩︎ Return/Enter
⌫ Delete
⌦ 向前删除键(Fn+Delete)
↑ 上箭头
↓ 下箭头
→ 右箭头
← 左箭头
⇞ Page Up(Fn+↑)
⇟ Page Down(Fn+↓)
Home Fn + ←
End Fn + →
⇥ 右制表符(Tab键)
⇤ 左制表符(Shift+Tab)
⎋ Escape (Esc)

mac输入特殊符号的方法

⚠️ ⌘+⌃+space 可以直接调出输入表情和特殊符号的选框, 开始显示的是emoji表情, 一直往下面拉滑或者点右上角的图标就是各种特殊符号咯.

Markdown操作

Markdown操作

公式单行用$公式$就可以

首先正常来一个公式,用符号$套两边就可以

显示效果如下 $ y =x+z$

如果想要公式居中,再套上一对就行:$$y = x^2 + z^3$$
显示效果如下:
$$
y = x^2 + z^3
$$
如果想要给公式后面添加编号,那么在公式后添加空格 + \tag{1}就可以了:
$$y = x^2 + z^3 \tag{1}$$
显示效果如下:
$$
y = x^2 + z^3 \tag{1}
$$

当然这只是最简单的使用,复杂的编辑方式还是查阅文档的好。

MAT工具应用之深堆和浅堆

MAT工具应用之深堆和浅堆

浅堆(Shallow Heap)

浅堆是指一个对象所消耗的内存(对象头+实例数据+对齐填充,不包括内部引用对象大小)

32位操作系统中
一个对象的对象头占用8字节,对象中的一个引用占4个字节,需要补齐位8的倍数
一维数组的为特殊对象,对象头占8个字节,加上4字节的长度数量,加上数组长度N*数组类型
String类型占用的字节数位40+2N+pandding(补齐为8的个数)

64位操作系统中
一个对象的对象头占用16字节,对象中的一个引用占8个字节,需要补齐位8的倍数
一维数组的为特殊对象,对象头占16个字节,加上8字节的长度数量,加上数组长度N*数组类型
String类型占用的字节数位64+2N+pandding(补齐为8的个数)

深堆(Retained Heap)

深堆表示一个对象被 GC 回收后,可以真实释放的内存大小(保留空间)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.idea4j.jvm.mat;
public class Point {
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.idea4j.jvm.mat;
public class Line {
private Point startPoint;//
private Point endPoint;
public Line(Point startPoint, Point endPoint) {
this.startPoint = startPoint;
this.endPoint = endPoint;
}
public Point getStartPoint() {
return startPoint;
}
public void setStartPoint(Point startPoint) {
this.startPoint = startPoint;
}
public Point getEndPoint() {
return endPoint;
}
public void setEndPoint(Point endPoint) {
this.endPoint = endPoint;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.idea4j.jvm.mat;
public class ShallowRetainedDump {
public static void main(String[] args) throws InterruptedException {
//
Point a = new Point(0, 0);
Point b = new Point(1, 1);
Point c = new Point(5, 3);
Point d = new Point(9, 8);
Point e = new Point(6, 7);
Point f = new Point(3, 9);
Point g = new Point(4, 8);
Line aLine = new Line(a, b);
Line bLine = new Line(a, c);
Line cLine = new Line(d, e);
Line dLine = new Line(f, g);
a = null;
b = null;
c = null;
d = null;
e = null;
Thread.sleep(1000000);
}
}

image-20200828200917670

如图(64位机器下),按照上面提到的 Line对象有两个Point对象组成 ,所以Line的浅

浅堆的大小为:对象头(16)+ 两个对象引用(8*2)=32,与图中数值不符。这是为什么呢?

这里是开启了指针压缩,开启指针压缩后,对象头占用字节为14,对象引用占用字节为4,那么,

浅堆的大小为:对象头(12)+ 两个对象引用(4*2)= 20,20不是8的倍数需要补齐,所以浅堆的大小为24.

1
2
* -XX:+UseCompressedOops开启指针压缩(默认) oop对象指针
* -XX:-UseCompressedOops关闭指针压缩

mylife170320

又是周一,和以往的周一样被闹铃叫醒,依旧在床上赖了一会儿才战胜疲惫挣扎着起了床。洗漱后出门,锁门的时候口里小声地默念着
:“锁了,锁了,锁了……”,这样给自己一个暗示,确定门锁了这个事实已经发生了,以免到了楼下甚至更远突然忘记是否锁门使得自己
还得回了再确认一遍。

空白地步行5分钟左右后就到了地铁站,地铁入口早就排起了长龙等待安检。宋家庄这个地方有个无包通道,这里
不带包就无需安检直接通过,为了节约上班时间,我基本上就不带包。刷卡进了站就往5号线的楼梯走,上班高峰期的自动扶梯是不运行的
楼梯上已经熙熙攘攘的挤满了人,一步一个台阶地下了楼梯,就看到一班地铁刚刚关了门,这是个好兆头,因为这代表下一班地铁我应该可以
上去。早上由于上班高峰,地铁几乎不得1分钟就会有一班。今天比较顺利,进门的时候关门的铃声还没响。5号线宋家庄是始发站,为了
给下几个站留位置,开门时间很短,在排队的人刚一半的时候就会关门,所以人们听到铃声会瞬间往车里挤。正是这个原因,几乎每天
都能听见吵架声,所幸今天我这个车厢没有。