Java常量引用导致内存泄漏?;
jvm jstat命令:Java常量引用导致内存泄漏?;,java,memory-leaks,Java,Memory Leaks,jvm jstat命令: jstat -gcutil 14378 2000 20 S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 8.04 0.00 87.61 9.06 96.45 94.34 702 13.804 8 2.521 16.325 Eclipse内存分析导航到代码块: public class MicrosoftC
jstat -gcutil 14378 2000 20
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
8.04 0.00 87.61 9.06 96.45 94.34 702 13.804 8 2.521 16.325
Eclipse内存分析导航到代码块:
public class MicrosoftConstant {
/**
* TODO TTS 请求头设置
*/
public static final List<Header> TTS_REQUEST_HEADERS = new ArrayList<Header>(){
{
add(new BasicHeader("Content-Type", "application/ssml+xml"));
add(new BasicHeader("X-Microsoft-OutputFormat", "xxx"));
add(new BasicHeader("X-Search-AppId", "xxx"));
add(new BasicHeader("X-Search-ClientID", "xxx"));
add(new BasicHeader("User-Agent", "xxx"));
add(new BasicHeader("Accept", "*/*"));
}
};
公共类MicrosoftConstant{
/**
*待办事项请求头设置
*/
公共静态最终列表TTS_请求_头=新ArrayList(){
{
添加(新的BasicHeader(“内容类型”、“应用程序/ssml+xml”);
添加(新BasicHeader(“X-Microsoft-OutputFormat”、“xxx”);
添加(新BasicHeader(“X-Search-AppId”、“xxx”);
添加(新的BasicHeader(“X-Search-ClientID”、“xxx”);
添加(新BasicHeader(“用户代理”、“xxx”);
添加(新的BasicHeader(“接受”)、“*/*”);
}
};
}
使用代码块的常量:
List<Header> headers = MicrosoftConstant.TTS_REQUEST_HEADERS;
headers.add(new BasicHeader("Ocp-Apim-Subscription-Key", microsoftConfig.getAppKey()));
headers.add(new BasicHeader("Authorization", "Bearer " + authToken));
InputStream audioStream = null;
HttpEntity httpEntity = httpApiService.doPost(microsoftConfig.getTtsUrl(), body.getBytes(), headers);
List headers=MicrosoftConstant.TTS\u请求\u头;
add(新的BasicHeader(“Ocp Apim订阅密钥”,microsoftConfig.getAppKey());
添加(新的BasicHeader(“授权”、“承载人”+authToken));
InputStream audioStream=null;
HttpEntity HttpEntity=httpApiService.doPost(microsoftConfig.gettsurl(),body.getBytes(),headers);
在大量访问期间,接口不会释放内存
我不知道如何解决这个问题。有人能提供解决方案吗?每次运行第二个代码块时,
TTS\u请求\u头
会在其中再获得两个项目。这意味着每个请求都会添加两个以上的头。TTS\u REQUEST\u HEADERS
对象的数据与final
不一致(只是指向对象的指针是final,不能更改,对象本身可以更改,列表可以增长),而.add
方法将使其越来越长
在为每个特定请求添加who标头之前,您可以.clone
克隆TTS\U请求\U标头。它是一个浅拷贝,这意味着您最初在TTS\u请求\u头中添加的基本阅读器将被重新使用
可能您必须将公共静态最终列表
更改为公共静态最终数组列表
,才能使克隆
正常工作。您不仅存在内存泄漏,还可能存在安全泄漏。问题是,对于您执行的每个请求,您都将头添加到列表TTS\u请求\u头
。这意味着随着每个请求,列表都会增加,而不会缩小
此外,您还可以使用,但在本例中,这并不是什么大问题
更糟糕的是,这意味着实际请求可能会多次重复某些头(这取决于HTTP客户端对重复头的处理),这可能会无意中泄漏有关以前请求的信息
此问题的解决方案是复制列表,将特定于请求的头添加到副本中,然后使用副本执行请求。为了确保不会无意中修改常量中的列表,请确保它不可修改(这样它实际上是一个常量)
为此,请将列表定义为不可修改的列表,例如:
public static final List<Header> TTS_REQUEST_HEADERS =
Collections.unmodifiableList(Arrays.asList(
new BasicHeader("Content-Type", "application/ssml+xml"),
new BasicHeader("X-Microsoft-OutputFormat", "xxx"),
new BasicHeader("X-Search-AppId", "xxx"),
new BasicHeader("X-Search-ClientID", "xxx"),
new BasicHeader("User-Agent", "xxx"),
new BasicHeader("Accept", "*/*")));
您的请求代码将变成:
// Copy the standard list of headers for this request
List<Header> headers = new ArrayList<>(MicrosoftConstant.TTS_REQUEST_HEADERS);
headers.add(new BasicHeader("Ocp-Apim-Subscription-Key", microsoftConfig.getAppKey()));
headers.add(new BasicHeader("Authorization", "Bearer " + authToken));
InputStream audioStream = null;
HttpEntity httpEntity = httpApiService.doPost(microsoftConfig.getTtsUrl(), body.getBytes(), headers);
//复制此请求的标准头列表
列表头=新的ArrayList(MicrosoftConstant.TTS\u请求\u头);
add(新的BasicHeader(“Ocp Apim订阅密钥”,microsoftConfig.getAppKey());
添加(新的BasicHeader(“授权”、“承载人”+authToken));
InputStream audioStream=null;
HttpEntity HttpEntity=httpApiService.doPost(microsoftConfig.gettsurl(),body.getBytes(),headers);
这是一个比我下面建议的更好的解决方案。我对新的不可修改列表集合函数不太熟悉。@clajCollections.unmodifiableList
包装现有列表并禁止通过该包装进行修改(因此不能通过包装修改基础列表,但可以由直接访问该列表的程序部分修改)。Java 9的List.of
生成一个不可变的列表。使用clone()
不是一个好主意,使用new ArrayList()
更好。TTS\u请求\u头不应该是可修改的,因此集合需要是不可变的(或者至少不能通过此引用进行修改)。克隆一个不可变的列表将导致一个不可变的列表,这将阻止添加新条目。它的实现确实创建了一个新的ArrayList,并将指向原始列表中项目的指针放在新列表中。无法修改原始列表。但是如果您更改原始列表引用的对象,这是不好的…是的,克隆可以在ArrayList
中正常工作,但是您希望防止修改常量中的列表(否则它将不是常量),以防止像OP现在这样的编程错误。防止修改会禁止克隆(或者至少会使克隆变得不太有用,因为不可修改列表的克隆(如果可能的话)也应该是不可修改的)。必须克隆常量列表的约定实际上是一个糟糕的约定。不可变列表更好!
// Copy the standard list of headers for this request
List<Header> headers = new ArrayList<>(MicrosoftConstant.TTS_REQUEST_HEADERS);
headers.add(new BasicHeader("Ocp-Apim-Subscription-Key", microsoftConfig.getAppKey()));
headers.add(new BasicHeader("Authorization", "Bearer " + authToken));
InputStream audioStream = null;
HttpEntity httpEntity = httpApiService.doPost(microsoftConfig.getTtsUrl(), body.getBytes(), headers);