内存优化,减轻GC压力

This commit is contained in:
2026-10-29 13:40:01 +08:00
parent b898e4c5be
commit c0e73bce55
6 changed files with 134 additions and 76 deletions
@@ -9,6 +9,7 @@ import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.util.ArrayList;
import java.util.HashMap;
@@ -35,6 +36,7 @@ import org.kne.cloud.network.monitor.MonitorData;
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorData;
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorDataImpl;
import org.kne.io.KNEChannels;
import org.kne.membandboost.MembandBoost;
public class KLALBRoutingProtocol extends Thread{
@@ -211,20 +213,15 @@ public class KLALBRoutingProtocol extends Thread{
while(true) {
try {
byte[]ca=MembandBoost.allocateUninitializedByteArray(65535);
DatagramPacket dgp=new DatagramPacket(ca, ca.length);
ds.receive(dgp);
//System.out.println(Arrays.toString( Arrays.copyOf( dgp.getData(),dgp.getLength())));
ByteArrayInputStream bi=new ByteArrayInputStream(dgp.getData(),0,dgp.getLength());
KLALBRoutingProtocolPacket kp=KLALBRoutingProtocolPacket.readKLALBPacketFromChannel(Channels.newChannel(bi));
KLALBRoutingProtocolPacket kp=receivePacket();
switch(kp.getType()) {
case KLALBRoutingProtocolPacket.RINFO_REQ:
RouterInfo rifr=netmap.get(router.getLocator().getAddress());
if(debug)
System.out.println("get Request from:"+dgp.getSocketAddress());
System.out.println("get Request from:"+kp.getFrom());
if(rifr!=null) {
writePacket( new RouterInfoPacket( rifr,false,-1), dgp.getSocketAddress());
writePacket( new RouterInfoPacket( rifr,false,-1), kp.getFrom());
if(debug)
System.out.println("response router info:"+rifr);
}else {
@@ -246,7 +243,7 @@ public class KLALBRoutingProtocol extends Thread{
netmap.put(rif.getLocator().getAddress(), rif);
noticeUpdate();
if(rifp.isFlood()) {
floodPacket( dgp.getSocketAddress(), rifp);
floodPacket( kp.getFrom(), rifp);
}
@@ -259,7 +256,7 @@ public class KLALBRoutingProtocol extends Thread{
break;
case KLALBRoutingProtocolPacket.JSON_DATA:
JsonDataPacket data=(JsonDataPacket) kp;
receivers.forEach((v)->{v.accept(dgp.getSocketAddress(),data);});
receivers.forEach((v)->{v.accept(kp.getFrom(),data);});
break;
default:
break;
@@ -276,7 +273,32 @@ public class KLALBRoutingProtocol extends Thread{
}
}
}
private static final ThreadLocal<ByteBuffer> LSDB_RX_BUFFER =
ThreadLocal.withInitial(() -> ByteBuffer.allocate(65535));
private KLALBRoutingProtocolPacket receivePacket() throws IOException {
// 2. 获取并重置缓冲区
ByteBuffer bbf = LSDB_RX_BUFFER.get();
bbf.clear();
// 3. 构造 DatagramPacket(注意这里要传底层 array 和 capacity)
DatagramPacket dgp = new DatagramPacket(bbf.array(), bbf.capacity());
// 4. 阻塞接收
ds.receive(dgp);
// 5. 限制缓冲区范围到实际收到的长度
bbf.limit(dgp.getLength());
bbf.position(0);
// 6. 直接用 KNEChannels 包装 ByteBuffer,避免 ByteArrayInputStream
KLALBRoutingProtocolPacket kp = KLALBRoutingProtocolPacket.readKLALBPacketFromChannel(
KNEChannels.newReadableChannel(bbf)
);
if(kp!=null)
kp.setFrom(dgp.getSocketAddress());
return kp;
}
private void floodPacket(SocketAddress except,RouterInfoPacket rifp) throws IOException {
long asn=rifp.getASN();
List<Neighbor>ln= router.getNeighbors();
@@ -304,20 +326,34 @@ public class KLALBRoutingProtocol extends Thread{
public void sendJsonPacketToAddress(JsonDataPacket pkt,SocketAddress dest) throws IOException {
writePacket(pkt,dest);
}
private void writePacket(KLALBRoutingProtocolPacket pkt,SocketAddress dest) throws IOException {
ByteArrayOutputStream bos=new ByteArrayOutputStream(65535);
KLALBRoutingProtocolPacket.writeKLALBPacketToChannel(Channels.newChannel(bos),pkt);
byte[]to=bos.toByteArray();
DatagramPacket dgpx=new DatagramPacket(to,to.length);
// 1. 在类成员变量处定义一个 64KB 的 ThreadLocal 缓冲区
// 注意:这里依然使用 65535,因为你说 LSDB 同步可能需要这么大
private static final ThreadLocal<ByteBuffer> LSDB_TX_BUFFER =
ThreadLocal.withInitial(() -> ByteBuffer.allocate(65535));
private void writePacket(KLALBRoutingProtocolPacket pkt, SocketAddress dest) throws IOException {
// 2. 从 ThreadLocal 获取,并清空状态
ByteBuffer bbf = LSDB_TX_BUFFER.get();
bbf.clear();
// 3. 使用 KNEChannels 绑定到 ByteBuffer,直接写入
// 这避免了 ByteArrayOutputStream 内部的动态扩容和拷贝
KLALBRoutingProtocolPacket.writeKLALBPacketToChannel(KNEChannels.newWritableChannel(bbf), pkt);
// 4. 翻转,准备读取数据
bbf.flip();
// 5. 直接拿底层的 byte[] 和真实的 limit 发送
DatagramPacket dgpx = new DatagramPacket(bbf.array(), bbf.limit());
dgpx.setSocketAddress(dest);
sendLock.lock();
try {
ds.send(dgpx);
}catch(BindException e) {
ds.send(dgpx);
} catch (BindException e) {
e.printStackTrace();
System.err.println("Cannot assign:"+dest);
}finally {
System.err.println("Cannot assign:" + dest);
} finally {
sendLock.unlock();
}
}