Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/87.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 清除列表并从本质上释放堆空间的更好方法_Java_Heap Memory - Fatal编程技术网

Java 清除列表并从本质上释放堆空间的更好方法

Java 清除列表并从本质上释放堆空间的更好方法,java,heap-memory,Java,Heap Memory,我有一个小型java应用程序,可以执行以下操作: 从队列读取消息(json字符串)并将其发送给发送者 发送方将收到的消息累加起来,当消息达到特定大小(比如说5k)时,发出http调用并发布这些消息 ApacheHTTP客户端用于发布消息,它是异步的,这意味着我不等待响应,并且在完成发布后会调用相应的回调方法 这是伪代码 Reader类:SomeProcessor.java public class SomeProcessor extends Processor { @Override

我有一个小型java应用程序,可以执行以下操作:

  • 从队列读取消息(json字符串)并将其发送给发送者
  • 发送方将收到的消息累加起来,当消息达到特定大小(比如说5k)时,发出http调用并发布这些消息
  • ApacheHTTP客户端用于发布消息,它是异步的,这意味着我不等待响应,并且在完成发布后会调用相应的回调方法
这是伪代码

Reader类:SomeProcessor.java

public class SomeProcessor extends Processor {
    @Override
    public void process(Messages m) {

    // some processing on m

    String jsonMessage = convertToJSON(m);

    getSender().send(jsonMessage);
    }
}
public class Processor {
    private HttpSender sender = null ;
    public Processor() {
        setSender(new HttpSender());
    }
    public HttpEventCollectorSender getSender() {
        return sender;
    }
    public void setSender(HttpEventCollectorSender sender) {
        this.sender = sender;
    }
}
基类:Processor.java

public class SomeProcessor extends Processor {
    @Override
    public void process(Messages m) {

    // some processing on m

    String jsonMessage = convertToJSON(m);

    getSender().send(jsonMessage);
    }
}
public class Processor {
    private HttpSender sender = null ;
    public Processor() {
        setSender(new HttpSender());
    }
    public HttpEventCollectorSender getSender() {
        return sender;
    }
    public void setSender(HttpEventCollectorSender sender) {
        this.sender = sender;
    }
}
发送者类:HttpSender.java

public class HttpSender {
    private List<String> eventsBatch = new ArrayList<String>(5000);

    public synchronized void send(final String message) {
        eventsBatch.add(message);
        if (eventsBatch.size() >= 5000) {
            flush(); // calls http post 
        }
    }

    public synchronized void flush() {
        if (eventsBatch.size() > 0) {
            postEventsAsync(eventsBatch);
        } 

        // since the above call is asynchronous after the post is called, I am assuming I should re-init the list, instead of clear. Is this correct?
        eventsBatch = new ArrayList<String>(5000); 
    }

    public void postEventsAsync(final List<String> events) {
        startHttpClient(); // make sure http client is started
        final String encoding = "utf-8";
        // create http request
        final HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader(AuthorizationHeaderTag, String.format(AuthorizationHeaderScheme, token));
        StringEntity entity = new StringEntity(String.join("", events), encoding);
        entity.setContentType(HttpContentType);
        httpPost.setEntity(entity);
        httpClient.execute(httpPost, new FutureCallback<HttpResponse>() {
            @Override
            public void completed(HttpResponse response) {
            // log to console   
            }

            @Override
            public void failed(Exception ex) {
            // just log to console  
            }

            @Override
            public void cancelled() {
            }
        });
    }
}
公共类HttpSender{
private List events sbatch=new ArrayList(5000);
公共同步无效发送(最终字符串消息){
eventsBatch.add(消息);
如果(eventsBatch.size()>=5000){
flush();//调用http post
}
}
公共同步的void flush(){
如果(eventsBatch.size()>0){
事件后同步(eventsBatch);
} 
//因为上面的调用在调用post后是异步的,所以我假设我应该重新初始化列表,而不是清除。这是正确的吗?
eventsBatch=新阵列列表(5000);
}
public void postEventsAsync(最终列表事件){
startHttpClient();//确保http客户端已启动
最终字符串编码=“utf-8”;
//创建http请求
最终HttpPost HttpPost=新HttpPost(url);
setHeader(AuthorizationHeaderTag,String.format(AuthorizationHeaderScheme,token));
StringEntity=新的StringEntity(String.join(“,事件),编码);
entity.setContentType(HttpContentType);
httpPost.setEntity(实体);
执行(httpPost,newfuturecallback(){
@凌驾
公共无效已完成(HttpResponse响应){
//登录到控制台
}
@凌驾
公共作废失败(例外情况除外){
//只需登录到控制台
}
@凌驾
公众假期取消(){
}
});
}
}
总的来说,我看到了非常高的内存利用率,并注意到即使在处理停止时,堆也不会被清除。我查看了堆转储,看到了用char[]表示的“json字符串”消息。我怀疑那些没有被GC’ed的字符串正在发生一些奇怪的事情

想法

Update-1:根据下面的注释,附加一个堆快照,其中处理暂停,堆空间仍然为4GB

更新-2:GC报告

这篇文章应该对你有所帮助你确定他们没有被GC'ed?或者由于可用堆相当大,可能还没有运行主要的GC?您是否启用了GC日志记录来查看自从json字符串被实际使用并释放后是否发生了GC?也不需要再次初始化列表。一个简单的
eventsBatch.clear()
应该可以job@XtremeBaumer-我总是使用5k元素初始化阵列。当数组的大小增加时复制数组在这里不是问题,那么调用clear有什么好处(我认为它只是将元素的引用设置为null,至少从代码来看是这样)?@cello-我使用以下命令--XX:+UseG1GC-XX:maxgcpausemilis=100-XX:initialingheapoccupencypercent=35-XX:+DisableExplicitGC。我注意到,自从我暂停处理以来,GC已经被启动。