线程、Arraylist对内存的影响-Java
我的输入数据是一个列表中有50000(或更多)封电子邮件,并且在收件人、抄送和密件抄送中有大量重复。因此,我需要从这个列表中提取唯一的消息 我必须比较消息的某些属性(From、to list和contain(仅字符串)),以确定它们是否相同 现在我将这50000条消息分成50个1000条消息的小列表,并在线程中运行每个小列表的副本 所有线程将其输出添加到一个列表中,最后我检查该线程中是否存在重复。 当我这样做的时候,我的JVM达到了1.25GB的内存 因此,如果我尝试推送超过50000条消息,就会出现内存不足错误 我有一个名为线程、Arraylist对内存的影响-Java,java,multithreading,jvm,out-of-memory,Java,Multithreading,Jvm,Out Of Memory,我的输入数据是一个列表中有50000(或更多)封电子邮件,并且在收件人、抄送和密件抄送中有大量重复。因此,我需要从这个列表中提取唯一的消息 我必须比较消息的某些属性(From、to list和contain(仅字符串)),以确定它们是否相同 现在我将这50000条消息分成50个1000条消息的小列表,并在线程中运行每个小列表的副本 所有线程将其输出添加到一个列表中,最后我检查该线程中是否存在重复。 当我这样做的时候,我的JVM达到了1.25GB的内存 因此,如果我尝试推送超过50000条消息,就
removedeplicate(消息数组,空白列表)
的方法,它将消息数组和空白列表作为输入,并在空白列表中返回唯一的消息。
这是我的代码:
public Message[] processForDeduplication(Message[] msgs) throws MessagingException, IOException, InterruptedException {
final List<Message> output = new ArrayList<Message>();
if(msgs.length < MAX_MSG){
output.addAll(removeDeduplication(msgs, new ArrayList<Message>()));
} else {
List<Thread> threads = new ArrayList<Thread>();
int index = 0, lastIndex = MAX_MSG;
while(index < msgs.length){
if(lastIndex >= msgs.length) {
lastIndex = msgs.length;
}
final Message[] temp = Arrays.copyOfRange(msgs, index, lastIndex);
Thread t = new Thread(new Runnable(){
@Override
public void run() {
try {
output.addAll(removeDeduplication(temp, new ArrayList<Message>()));
} catch (MessagingException ex) {
logger.error(EmailComparator.class.getName() + ex);
} catch (IOException ex) {
logger.error(EmailComparator.class.getName() + ex);
}
}
});
t.start();
threads.add(t);
index = lastIndex;
lastIndex = lastIndex + MAX_MSG;
}
for(Thread t: threads){
while(t.isAlive()){
Thread.sleep(100);
}
}
threads = null;
}
List<Message> results = removeDeduplication(convertToArray(output), new ArrayList<Message>());
return convertToArray(results);
}
public Message[]processForDeduplication(Message[]msgs)抛出MessaginException、IOException、InterruptedException{
最终列表输出=新的ArrayList();
如果(msgs.length=msgs.length){
lastIndex=msgs.length;
}
最终消息[]temp=Arrays.copyOfRange(msgs、index、lastIndex);
线程t=新线程(新的可运行线程(){
@凌驾
公开募捐{
试一试{
addAll(removededApplication(temp,newarraylist());
}捕获(消息例外){
logger.error(EmailComparator.class.getName()+ex);
}捕获(IOEX异常){
logger.error(EmailComparator.class.getName()+ex);
}
}
});
t、 start();
添加(t);
指数=最新指数;
lastIndex=lastIndex+最大值;
}
用于(螺纹t:螺纹){
while(t.isAlive()){
睡眠(100);
}
}
线程=null;
}
列表结果=RemovedApplication(convertToArray(输出),new ArrayList());
返回到阵列(结果);
}
我正试图微调我的代码,以提高内存和性能。
现在完成50000条记录大约需要12-15秒,我希望是5-6秒。我不确定你的
消息是什么,所以我假设它是javax.mail.Message
。我创建了一个包装器对象,按照您的指定检查消息的相等性。此对象将from
和to
数组缓存为Set
s-这允许更快的相等比较,因为Set
s有一个O(1)contains方法。
包装器还缓存hashCode
,这样就不必由集合重新计算它
public static class MessageWrapper {
private final Message message;
private final Set<Address> from;
private final Set<Address> to;
private final Object content;
private final int hashCode;
public MessageWrapper(Message message) throws MessagingException, IOException {
this.message = message;
this.from = new HashSet<Address>(Arrays.asList(message.getFrom()));
this.to = new HashSet<Address>(Arrays.asList(message.getRecipients(Message.RecipientType.TO)));
this.content = message.getContent();
this.hashCode = calcHashCode();
}
public Message getMessage() {
return message;
}
private int calcHashCode() {
int hash = 7;
hash = 37 * hash + (this.from != null ? this.from.hashCode() : 0);
hash = 37 * hash + (this.to != null ? this.to.hashCode() : 0);
hash = 37 * hash + (this.content != null ? this.content.hashCode() : 0);
return hash;
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MessageWrapper other = (MessageWrapper) obj;
if (this.from != other.from && (this.from == null || !this.from.equals(other.from))) {
return false;
}
if (this.to != other.to && (this.to == null || !this.to.equals(other.to))) {
return false;
}
if (this.content != other.content && (this.content == null || !this.content.equals(other.content))) {
return false;
}
return true;
}
}
这有点混乱,因为您必须在最后将内容转换回消息[]
显然,如果您的消息
不是javax.mail.Message
那么实现可能会有所不同。您甚至可以直接在所讨论的类上实现equals
和hashCode
。您可以在每个循环中创建一个新线程。创建一个线程,并将实例添加到队列中以供其处理。我在这里解决了一个非常类似的问题:@Legend,但这意味着一个线程完成所有工作,我放松了多线程处理,因此需要很长时间。哇,你设计得太过火了。50k项是一个很小的列表,只需将它们添加到一个带有适当比较器的树集中,您就完成了。@bhavin Perceptions'解决方案说使用比较器。比较器允许您获取两个对象并检查它们是否相等或排序。您也可以在消息对象上实现.equals()(和.hashCode()),然后将所有内容放入哈希集中以删除重复项。正如我预料的那样,散列不能正常工作。它为每个相同的对象生成不同的散列,因此它永远不会工作。但是谢谢你的时间和帮助。正如我所说的,你需要根据自己的需要修改它,准确地计算出什么是平等的,并适当地编写方法。创建一个包含2-3条消息的简单测试用例,并适当地调整方法。
public Message[] processForDeduplication(final Message[] messages) throws MessagingException, IOException {
final Set<MessageWrapper> messageWrappers = new HashSet<MessageWrapper>(messages.length, 1.0f);
for (final Message m : messages) {
messageWrappers.add(new MessageWrapper(m));
}
final List<Message> ms = new ArrayList<Message>(messages.length);
for (final MessageWrapper wrapper : messageWrappers) {
ms.add(wrapper.getMessage());
}
return ms.toArray(new Message[messages.length]);
}