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