java 堆外内存是什么,请教java堆外内存泄漏分析定位方法
很多朋友对于java 堆外内存是什么和请教java堆外内存泄漏分析定位方法不太懂,今天就由小编来为大家分享,希望可以帮助到大家,下面一起来看看吧!
Java养成什么样的编程习惯可以有利于GC呢
善用 weakrefrence(WeakHashMap)和 softrefrence;当对象的强引用都不在以后,如果HashMap或者 ArrayList里对它是弱引用,被引用的对象会在下次GC时被回收关于 object pooling,虽然是很过时的技术,创建小对象的开销也越来越小(至少归功于TLAB和堆空间的分区),维护一个 pool提供各种接口可能还开销更大,但对于数据库连接对象的创建、线程的创建,object pooling都还是管用的,手动置空,这个只在个别情况下有意义,大家都知道了Immutability的问题,多次使用不可变的对象不一定不好。当在一个容器里引用另一个对象的时候,如果要替换引用的对象,要么在原容器里替换引用(容器可变),要么创建新的容器(容器不可变)。重用容器似乎更高效,但是请注意,如果容器对象已经在老年区,重用就会引入老对象对新对象的引用,复杂化了GC操作;而创建新的容器则不会有这个问题。
spark内存溢出及其解决方案
1、你在工作当中有遇到内存溢出问题吗?你是如何解决的?
回答思路:先解释spark的内存模型,再分情况介绍不同情况下的解决方案。总体思想是根据内存模型找出不够的那一块内存,要么提升占比,要么整体增加。
oom通常出现在execution内存中,因为storage这块内存在放满之后,会直接丢弃内存中旧的数据,对性能有点影响但不会导致oom。存储内存和执行内存可以互相借用内存空间。
而spark的oom问题主要分为三种情况:
①map执行后的内存溢出
--场景:maptask所运行的executor内存溢出。
增加堆内内存,申请的堆外内存也会随之增加
--executor-memory
增加堆外内存
--conf spark.excutor.memoryoverhead 2048
默认申请的堆外内存是Executor内存的10%。
②shuffle后内存溢出
reduce task去map一边拉取数据,一边聚合。reduce端有一块聚合内存,executor memory*0.2
解决方案:增加reduce聚合内存的比例,设置spark.shuffle.memoryfraction
增加executor memory的大小
减少reduce task每次拉取的数据量,设置spark.reducer.maxSizeInFlight 24m
③driver内存溢出
--场景一:用户在Dirver端口生成大对象,比如创建了一个大的集合数据结构
解决思路:Ⅰ将大对象转换成Executor端加载,比如调用sc.textfile
Ⅱ评估大对象占用的内存,增加dirver-menory的值
--场景二:从Executor端收集数据(collect)回Dirver端
解决思路:Ⅰ本身不建议将大的数据从executor端,collect回来。建议将driver端对collect回来的数据所作的操作,转换成executor端rdd操作
Ⅱ若无法避免,估算collect需要的内存,相应增加driver-memory的值
--场景三:spark自身框架的消耗
主要由spark UI数据消耗,取决于作业的累计task个数
解决思路:Ⅰ从hdfs load的parition是自动计算,但在过滤之后,已经大大减少了数据量,此时可以缩小partitions。
Ⅱ通过参数spark.ui.retainedStages/spark.ui.retainedjobs控制(默认1000)
2、shuffle file not found可能是什么原因导致的报错?
产生该报错的原因可能是后一个stage的task从上一个stage的task所在的executor拉取数据,但是上一个stage正在执行GC,导致数据没有拉渠道,出现该错误。可以通过调整拉取的次数和间隔时间来避免此类事件发生。
val conf=new SparkConf()
.set("spark.shuffle.io.maxRetries","6')
.set("spark.shuffle.io.retrywait","60s")
3、栈溢出?
yarn-client模式下,Dirver是运行在本地机器上的,spark使用的jvm的permGen是128m,可能在client上测试没有问题
yarn-cluster模式下,Dirver是运行在集群的某个节点上,使用的是没有经过配置的默认配置,PermGen永久代大小为82m。运行时报栈溢出。
--解决方案:在spark-submit脚本中对相关参数进行设置
--conf spark.dirver.extraJavaOptions="-xx:PerSize=128M-xx:MaxPermSize=256m"
请教java堆外内存泄漏分析定位方法
4.Java中参数都是传值的。
对于基本类型,大家基本上没有异议,但是对于引用类型我们也不能有异议。
Java内存泄露情况
JVM回收算法是很复杂的,我也不知道他们怎么实现的,但是我只知道他们要实现的就是:对于没有被引用的对象是可以回收的。所以你要造成内存泄露就要做到:
持有对无用对象的引用!
不要以为这个很轻易做到,既然无用,你怎么还会持有它的引用?既然你还持有它,它怎么会是无用的呢?
以下以堆栈更经典这个经典的例子来剖析。
Java代码
public class Stack{
private Object[] elements=new Object[10];
private int size= 0;
public void push(Object e){
ensureCapacity();
elements[size++]= e;
}
public Object pop(){
if( size== 0)
throw new EmptyStackException();
return elements[--size];
}
private void ensureCapacity(){
if(elements.length== size){
Object[] oldElements= elements;
elements= new Object[2* elements.length+1];
System.arraycopy(oldElements,0, elements, 0, size);
}
}
}
上面的原理应该很简单,假如堆栈加了10个元素,然后全部弹出来,虽然堆栈是空的,没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件:无用,无法回收。
但是就是存在这样的东西也不一定会导致什么样的后果,假如这个堆栈用的比较少,也就浪费了几个K内存而已,反正我们的内存都上G了,哪里会有什么影响,再说这个东西很快就会被回收的,有什么关系。下面看两个例子。
例子1
Java代码
public class Bad{
public static Stack s=Stack();
static{
s.push(new Object());
s.pop();//这里有一个对象发生内存泄露
s.push(new Object());//上面的对象可以被回收了,等于是自愈了
}
}
因为是static,就一直存在到程序退出,但是我们也可以看到它有自愈功能,就是说假如你的Stack最多有100个对象,那么最多也就只有100个对象无法被回收其实这个应该很轻易理解,Stack内部持有100个引用,最坏的情况就是他们都是无用的,因为我们一旦放新的进取,以前的引用自然消失!
例子2
Java代码
public class NotTooBad{
public void doSomething(){
Stack s=new Stack();
s.push(new Object());
//other code
s.pop();//这里同样导致对象无法回收,内存泄露.
}//退出方法,s自动无效,s可以被回收,Stack内部的引用自然没了,所以
//这里也可以自愈,而且可以说这个方法不存在内存泄露问题,不过是晚一点
//交给GC而已,因为它是封闭的,对外不开放,可以说上面的代码99.9999%的
//情况是不会造成任何影响的,当然你写这样的代码不会有什么坏的影响,但是
//绝对可以说是垃圾代码!没有矛盾吧,我在里面加一个空的for循环也不会有
//什么太大的影响吧,你会这么做吗?
}
文章分享结束,java 堆外内存是什么和请教java堆外内存泄漏分析定位方法的答案你都知道了吗?欢迎再次光临本站哦!