gpt4 book ai didi

Java/Android SDK 内存泄漏使用 inputStream.available()

转载 作者:行者123 更新时间:2023-11-30 11:00:30 31 4
gpt4 key购买 nike

我写了一个 Java 类,它有一个现有的 tcp 连接池和一个在这些连接上循环的工作线程。在检查是否需要处理来自对等点的信息的函数中,它调用了 inputStream.available()。我在看内存追踪器,它一直在上升。当我记录分配时,有数百个 android.util.MutableInt 对象分配在

at libcore.io.IoBridge.available(IoBridge.java:57)
at java.net.PlainSocketImpl.available(PlainSocketImpl.java:128)
at java.net.PlainSocketImpl$PlainSocketInputStream.available(PlainSocketImpl.java:225)
at myClass

有问题的代码:

void someFunction() {
(new Thread(){
public void run() {
try {
while(true) {
for(int i=0; i<peers.size(); i++) {
peer = peers.get(i);
peer.doWorkListen();
peer.doWorkSend();
}
Thread.sleep(1);
}
catch (Exception e) {}
}).start();
}

void peer.doWorkListen() {
if(inputStream.available() > 0) {
//Read and process input
}
}

最佳答案

您遇到的不是内存泄漏,而是垃圾收集器无法跟上您每秒创建的大量垃圾邮件。*最终,您会发现您的应用程序在 gc 调用时会暂时卡住大量删除不需要的对象的停止世界技术。

从您的代码中,我可以看出您正在尝试使用单个线程从多个流中轮询可用性。我认为您在这里创建的是 Java/Android 的非阻塞 I/O 的非常初级和低效的实现。

鉴于堆栈跟踪,我还假设您在这种情况下正在使用套接字。将 ServerSocketChannelSocketChannelSelector 一起使用可以为您提供所需的功能。下面提供了一个仅使用 Selector 和 SocketChannel 的示例实现(如果这是服务器端代码,您应该使用相同的逻辑实现 ServerSocketChannel)。

public class Foo implements Runnable{
private final Selector selector;
private volatile boolean run;

public Foo() throws IOException{
selector = Selector.open();
run = true;
}

public void registerChannel(SocketChannel channel) throws IOException{
channel.configureBlocking(false);
// Optionally use a selection key for write as well
channel.register(selector, SelectionKey.OP_READ);
}

public void shutdown(){
run = false;
selector.wakeup();
try{
selector.close();
}catch(IOException ignore){}
}

public void run(){
while(run){
try{
int readyCount = selector.select();

// Selector was interrupted or manually woken up
if(readyCount == 0){
// handle appropriately
}else{
Iterator<SelectionKey> iterKeys = selector.selectedKeys().iterator();

while(iterKeys.hasNext()){
SelectionKey key = iterKeys.next();

if(key.isReadable()){
SocketChannel chn = (SocketChannel) key.channel();

// Process input here
}else{
// We aren't interested in non-readable channels atm
}

// Very important
iterKeys.remove();
}
}
}catch(IOException ex) {
// handle selector exception
}
}
}
}

Foo 类充当您创建的线程的可运行对象,并以高效的方式多路复用 SocketChannel阻塞(相对于快速轮询)套接字,直到有一个可用为止。这不仅消除了创建大量对象的问题,还消除了 available()** 的使用,后者在不同平台上可能不可靠。这种设计模式还有一个额外的好处,即它可能比使用大量套接字的方法更快,因为它不必按顺序遍历套接字列表。

查看 Selector 上的教程和 SocketChannel以及 alternative example以获得更深入的了解。


* 我只能跟踪 available() 的实现到 IoBridge.available(fd) (我没有 IoBridge 的来源)因此不能完全排除内存泄漏,尽管这种可能性极小。

** available() 的实现差异很大,不应用作可用数据量的绝对指标。根据我的发现,java 的 PlainSocketImpl 硬编码为套接字返回 0。即使 android 通过 IoBridge.available(fd) 有一个有效的 available(),你也可以用非阻塞 I/O 来回避这个问题,如果它真的是libcore 内存泄漏。

关于Java/Android SDK 内存泄漏使用 inputStream.available(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31498277/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com