CopyOnWriteArrayList内存占用过多

在这里插入图片描述

目录

    • 一、CopyOnWriteArrayList
    • 二、CopyOnWriteArrayList的适用场景
    • 三、CopyOnWriteArrayList内存占用过多的解决方法
    • 四、CopyOnWriteArrayList.add()源码分析

大家好,我是哪吒。

一、CopyOnWriteArrayList

CopyOnWriteArrayList是Java中的一个线程安全的ArrayList,它在每次修改时都会创建一个新的数组,并将原数组的引用赋值给新数组,从而达到线程安全的目的。由于它不断地创建新的数组并保留旧数组,因此内存占用可能会比较多。

CopyOnWriteArrayList具有以下特点:

  1. 线程安全:CopyOnWriteArrayList使用读写锁来确保并发访问时的线程安全性,因此可以在多线程环境下使用。
  2. 内存占用较高:由于它在每次修改操作时都会创建一个新的数组,并且会保留旧数组,因此内存占用可能会比较多。
  3. 适合读密集型应用:由于它只会在写操作时进行数组复制,因此对于读密集型的应用,使用CopyOnWriteArrayList可以减少锁竞争,提高并发性能。
  4. 不支持写操作:CopyOnWriteArrayList不支持add()和remove()方法,因为这些操作需要修改底层数组,从而导致所有线程都看到不一致的结果。因此,如果需要执行写操作,可以考虑使用其他的线程安全的数据结构,如Collections.synchronizedList()。

总之,CopyOnWriteArrayList适合读密集型应用,并且在写操作时需要注意内存占用问题。如果需要执行写操作,可以考虑使用其他的线程安全的数据结构。

二、CopyOnWriteArrayList的适用场景

CopyOnWriteArrayList主要适用于读多写少的场景,例如配置信息、缓存等数据的读取和更新操作。由于写操作的时候会进行数组复制,会消耗内存,如果原数组的内容比较多的情况下可能导致young gc或者full gc。因此,对于读操作非常频繁,而写操作相对较少的场景,使用CopyOnWriteArrayList可以提供较好的并发性能和线程安全性。

需要注意的是,CopyOnWriteArrayList在写操作中使用了ReentrantLock锁来保证线程安全,并替换原array属性;但是在读的时候直接读取array,可能会发生在写操作替换array前后,从而引发数据不一致的问题。因此,在使用CopyOnWriteArrayList时需要注意以下几点:

  1. 如果写操作未完成,那么直接读取原数组的数据是不一致的。
  2. 如果写操作完成,但是引用还未指向新数组,那么也是读取原数组数据是不一致的。
  3. 如果写操作完成,并且引用已经指向了新的数组,那么直接从新数组中读取数据是一致的。

总之,CopyOnWriteArrayList适用于读多写少且数据一致性要求较高的场景。

三、CopyOnWriteArrayList内存占用过多的解决方法

  1. 尽量避免在CopyOnWriteArrayList中进行频繁的修改操作。如果可能的话,可以尝试将这些修改操作集中在一起进行,从而减少数组的创建和销毁次数。
  2. 使用其他的线程安全的数据结构,比如Collections.synchronizedList()。这种数据结构使用的内存开销通常比CopyOnWriteArrayList小。
  3. 如果必须要使用CopyOnWriteArrayList,可以使用WeakReference来减少内存占用。具体来说,可以将数组元素使用WeakReference管理,当数组不再被引用时,垃圾回收器可以将其回收,从而释放内存。

另外,你还可以通过查看JVM的内存快照(比如使用jstat工具)来分析内存占用过多的原因。这可以帮助你更好地了解内存占用情况并采取相应的措施。

四、CopyOnWriteArrayList.add()源码分析

public boolean add(E e) {
	// 获取独占锁
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    	// 获取array
        Object[] elements = getArray();
        int len = elements.length;
        // 复制array到新数组,添加元素到新数组
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        // 替换数组
        setArray(newElements);
        return true;
    } finally {
	    // 释放锁
        lock.unlock();
    }
}

CopyOnWriteArrayList内部定义了一个内部array数组,然后复制array到新数组,添加元素到新数组。所有的读操作都是基于新的array对象进行的。

private transient volatile Object[] array;

final Object[] getArray() {
    return array;
}

因为上了独占锁ReentrantLock,如果多个线程调用add()方法,只会有一个线程会获得到该锁,其他线程被阻塞,直至锁被释放, 由于加了锁,所以整个操作的过程是原子性操作。

由于每次写入的时候都会对数组对象进行复制,复制过程不仅会占用双倍内存,还需要消耗 CPU 等资源,如果要保存大量元素,并放任其成长,内存和CPU将面临重大考验,场面堪比金角巨兽,后果不堪设想。

对 CopyOnWriteArrayList 每一次修改,都会重新创建一个大对象,并且原来的大对象也需要回收,这都可能会触发 GC,如果超过老年代的大小则容易触发Full GC,引起应用程序长时间停顿。

在这里插入图片描述

🏆哪吒多年工作总结:Java学习路线总结,搬砖工逆袭Java架构师

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/138476.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

负债1320万美元的【思宏集团/Neo-Concep】申请900万美元纳斯达克IPO上市

来源:猛兽财经 作者:猛兽财经 猛兽财经获悉,总部位于香港的思宏集团Neo-Concept International Group Holdings Limited(简称:思宏集团)近期已向美国证券交易委员会(SEC)提交招股书&#xff0c…

基于SpringBoot+Redis的前后端分离外卖项目-苍穹外卖(四)

编辑员工和分类模块功能开发 1. 编辑员工1.1 需求分析与设计1.1.1 产品原型1.1.2 接口设计 1.2 代码开发1.2.1 回显员工信息功能1.2.2 修改员工信息功能 1.3 功能测试 2. 分类模块功能开发2.1 需求分析与设计2.1.1 产品原型2.1.2 接口设计2.1.3 表设计 2.2 代码实现2.2.1 Mappe…

ip数据包

数据报文格式 首部 版本(Version) 版本字段占4bit,通信双方使用的版本必须一致。对于IPv4,字段的值是4。 首部长度(Internet Header Length, IHL) 占4bit,首部长度说明首部有多少…

Clickhouse学习笔记(13)—— Materialize MySQL引擎

该引擎用于监听 binlog 事件,类似于canal、Maxwell等组件 ClickHouse 20.8.2.3 版本新增加了 MaterializeMySQL 的 database 引擎,该 database 能映射到 MySQL中的某个database ,并自动在ClickHouse中创建对应ReplacingMergeTree。 ClickHous…

MPLS VPN详解

了解MPLS VPN之前,要先了解一下MPLS。 了解MPLS之前,先回顾一下基于MAC地址的交换和基于IP地址的路由转发。 (上篇主要是介绍基于mac地址的交换、基于IP地址的路由转发、MPLS详解) (下篇主要是MPLS VPN的网络结构、…

前端基础------margin上下传递

1,出现的原因及解决方法 ◼ margin-top传递 如果块级元素的顶部线和块级父元素的顶部线重叠,那么这个块级元素的margin-top值会传递给父元素 ◼ margin-bottom传递 如果块级元素的底部线和块级父元素的底部线重叠,并且父元素的高度是…

【Proteus仿真】【51单片机】停车场车位管理系统

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器,使用按键、LED、蜂鸣器、LCD1602、红外传感器、74HC595模块等。 主要功能: 系统运行后,LCD1602显示进入、驶出、剩余车位数&am…

1000道精心打磨的计算机考研题,408小伙伴不可错过

提示:408考研人看过来,超精选计算机考研1000题! 文章目录 前言1. 为什么是1000题?2. 有什么优势?【练学结合,助力强化】【难度适中,但不刁钻】【题目新颖,独具匠心】【考题预测&…

学生五科成绩统计

随机生成10名学生姓名(包括自己)和五科成绩,将数据存入*.csv,读取保存的*.csv文本数据计算每个学生总分和平均分,并存入*.csv文本;打印总分排名前三学生信息;查找10学生各科最高最低分、中位分、平均分。 (笔记模板由p…

Python参数传递,从入门到精通

Python是一种非常灵活的编程语言,以多种方式定义和调用函数。其中一个关键方面是参数传递的灵活性。在Python中,可以通过位置、关键字、默认值和可变长度参数等多种方式来传递参数。 1. 位置参数 位置参数是最常见的参数传递方式。当调用一个函数时&am…

curl使用

文章目录 前言一、curl use case二、下载操作我使用第一种方式:不验证证书,果然下载下来了。而且是下载到当前的工作文件夹。C:\Users\xxx\test.zip如果自己想指定文件地址 前言 使用 curl 工具 一、curl use case Simple Usage Get the main page fro…

ts学习02-数据类型

新建index.html <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </h…

享受JoySSL证书买赠活动,提升您的网站安全和用户信任!

互联网时代&#xff0c;网站安全性和用户信任度变得尤为重要。作为您网站的保护盾&#xff0c;SSL证书是确保数据传输安全和建立可信连接的关键组成部分。在这个背景下&#xff0c;我们非常激动地宣布JoySSL平台推出了令人兴奋的SSL证书买赠活动&#xff1a;买二送一&#xff0…

web3 React dapp进行事件订阅

好啊&#xff0c;上文web3 React Dapp书写订单 买入/取消操作 我们已经写好了 填充和取消订单 这就已经是非常大的突破了 但是 留下了一个问题 那就是 我们执行完之后 订单的数据没有直接更新 每次都需要我们手动刷新 才能看到结果 那么 今天我们就来看解决这个问题的事件订阅 …

CSS常用示例100+ 【目录】

目前已有文章 11 篇 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花边是描述了一些CSS相关…

来看看电脑上有哪些不为人知的小众软件?

​ 电脑上的各类软件有很多&#xff0c;除了那些常见的大众化软件&#xff0c;还有很多不为人知的小众软件&#xff0c;专注于实用功能&#xff0c;简洁干净、功能强悍。 1.桌面停靠栏工具——BitDock ​ BitDock是一款运行在Windows系统中的桌面停靠栏工具&#xff0c;功能实…

ASUS华硕ROG枪神2笔记本GL504GS原厂Win10预装OEM系统

链接&#xff1a;https://pan.baidu.com/s/1sqm9NXopSe_mg8v--7fzzA?pwd9dru 提取码&#xff1a;9dru 原厂系统自带显卡网卡声卡等所有驱动、出厂主题壁纸、系统属性华硕专属LOGO标志、Office办公软件、MyASUS华硕电脑管家、控制中心等预装程序 由于时间关系,绝大部分资料…

Nginx学习(在 Docker 中使用 Nginx)

1. 安装Nginx 使用 docker pull nginx 下载最新的 Nginx Docker 镜像。 下载完毕后&#xff0c;使用 docker run -d -p 80:80 --name nginx nginx&#xff0c;即可启动 Nginx 容器。其中&#xff0c;-p 80:80 表示将容器的 80 端口映射到 主机的 80 端口&#xff1b;--name ng…

虹科方案 | 汽车电子电气架构设计仿真解决方案

来源&#xff1a;虹科汽车电子 虹科方案 | 汽车电子电气架构设计仿真解决方案 导读 本文将介绍面向服务&#xff08;SOA&#xff09;的汽车TSN网络架构&#xff0c;并探讨RTaW-Pegase仿真与设计软件在TSN网络设计中的应用。通过RTaW将设计问题分解&#xff0c;我们可以更好地理…

前端面试之事件循环

什么是事件循环 首先&#xff0c; JavaScript是一门单线程的语言&#xff0c;意味着同一时间内只能做一件事&#xff0c;这并不意味着单线程就是阻塞&#xff0c;而是实现单线程非阻塞的方法就是事件循环 在JavaScript中&#xff0c;所欲任务都可以分为&#xff1a; 同步任务…