Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/327.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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
线程、Arraylist对内存的影响-Java_Java_Multithreading_Jvm_Out Of Memory - Fatal编程技术网

线程、Arraylist对内存的影响-Java

线程、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条消息,就

我的输入数据是一个列表中有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]);
}