-
JAVA堆:对象内存分配的地方,内存垃圾回收的主要区域,所有线程共享。可分为新生代,老生代。
-
方法区:用于存储已经被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。Hotspot中的“永久代”。
-
运行时常量池:方法区的一部分,存储常量信息,如各种字面量、符号引用等。
-
直接内存:并不是JVM运行时数据区的一部分, 可直接访问的内存, 比如NIO会用到这部分。
按照JVM规范,除了程序计数器不会抛出OOM外,其他各个内存区域都可能会抛出OOM。
最常见的OOM情况有以下三种:
- java.lang.OutOfMemoryError: Java heap space
java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。
- java.lang.OutOfMemoryError: PermGen space
java永久代溢出,即方法区溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。此种情况可以通过更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。另外,过多的常量尤其是字符串也会导致方法区溢出。
- java.lang.StackOverflowError
不会抛OOM error,但也是比较常见的Java内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。
内存抖动
短时间内大量的对象被创建,导致可用内存不足,从而引起频繁gc回收对象,这种已用内存忽高忽低的现象就叫内存抖动。由于gc的过程会 “stop the world” 停止其他的一切工作,gc太频繁无疑会造成界面卡顿,而且gc回收后可能会产生内存碎片,如果这时其他线程需要申请大块内存还有可能发生OOM,所以内存抖动的情况必须要避免。
什么情况会出现内存抖动呢?
for循环内使用了+进行字符串拼接
这是很常见的字符串拼接操作,通过查看字节码文件可以看出+的拼接字符串实际上是创建StringBuilder对象进行拼接,这样就会出现大量创建对象频繁GC,导致内存抖动。
内存抖动一定是锯齿状吗?
看下面一个实例,实现IOS小菊花的功能
public class IOSStyleLoadingView extends View {
private Context mContext;
private float mStrokeWidth;
private float northwestXStart = 264.57f;
private float northwestYStart = 264.71f;
private float northwestXEnd = 193.72f;
private float northwestYEnd = 194.14f;
private float northXStart = 300;
private float northYStart = 250;
private float northXEnd = 300;
private float northYEnd = 150;
private float notheastXStart = 335.25f;
private float notheastYStart = 264.54f;
private float notheastXEnd = 405.76f;
private float notheastYEnd = 193.63f;
private float eastXStart = 350;
private float eastYStart = 300f;
private float eastXEnd = 450;
private float eastYEnd = 300;
private float southeastXStart = 335.36f;
private float southeastYStart = 335.34f;
private float southeastXEnd = 406.10f;
private float southeastYEnd = 406.02f;
private float southXStart = 300.03f;
private float southYStart = 345f;
private float southXEnd = 300;
private float southYEnd = 450;
private float southwestXStart = 264.68f;
private float southwestYStart = 335.39f;
private float southwestXEnd = 194.06f;
private float southwestYEnd = 406.19f;
private float westXStart = 250;
private float westYStart = 300;
private float westXEnd = 150;
private float westYEnd = 300;
String colorStr[] = new String[]{
“#ffff00”,
“#ff3300”,
“#ccff00”,
“#ff00cc”,
“#ccffff”,
“#cc99ff”,
“#99ff66”,
“#993300”
};
private ValueAnimator valueAnimator;
private int currentColor = 0;
public IOSStyleLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
this.mStrokeWidth = UIUtils.dp2px(this.mContext, 5);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Sample test1=new Sample(“测试1”);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(this.mStrokeWidth);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
Path p0 = new Path();
paint.setColor(Color.parseColor(colorStr[0]));
p0.moveTo(northwestXStart, northwestYStart);
p0.lineTo(northwestXEnd, northwestYEnd);
canvas.drawPath(p0, paint);
Path p1 = new Path();
paint.setColor(Color.parseColor(colorStr[1]));
p1.moveTo(northXStart, northYStart);
p1.lineTo(northXEnd, northYEnd);
canvas.drawPath(p1, paint);
Path p2 = new Path();
paint.setColor(Color.parseColor(colorStr[2]));
p2.moveTo(notheastXStart, notheastYStart);
p2.lineTo(notheastXEnd, notheastYEnd);
canvas.drawPath(p2, paint);
Path p3 = new Path();
paint.setColor(Color.parseColor(colorStr[3]));
p3.moveTo(eastXStart, eastYStart);
p3.lineTo(eastXEnd, eastYEnd);
canvas.drawPath(p3, paint);
Path p4 = new Path();
paint.setColor(Color.parseColor(colorStr[4]));
p4.moveTo(southeastXStart, southeastYStart);
p4.lineTo(southeastXEnd, southeastYEnd);
canvas.drawPath(p4, paint);
Path p5 = new Path();
paint.setColor(Color.parseColor(colorStr[5]));
p5.moveTo(southXStart, southYStart);
p5.lineTo(southXEnd, southYEnd);
canvas.drawPath(p5, paint);
Path p6 = new Path();
paint.setColor(Color.parseColor(colorStr[6]));
p6.moveTo(southwestXStart, southwestYStart);
p6.lineTo(southwestXEnd, southwestYEnd);
canvas.drawPath(p6, paint);
Path p7 = new Path();
paint.setColor(Color.parseColor(colorStr[7]));
p7.moveTo(westXStart, westYStart);
p7.lineTo(westXEnd, westYEnd);
canvas.drawPath(p7, paint);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
startAnimation();
}
public void startAnimation() {
valueAnimator = ValueAnimator.ofInt(7, 0);
valueAnimator.setDuration(400);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if ((int) animation.getAnimatedValue() != currentColor){
String b[] = new String[colorStr.length];
for (int c = 0, size = colorStr.length - 1; c < size; c++) {
b[c + 1] = colorStr[c];
}
b[0] = colorStr[colorStr.length - 1];
colorStr = b;
invalidate();
currentColor = (int) animation.getAnimatedValue();
}
}
});
valueAnimator.start();
}
}
内存分配
这是一个看起来相对平滑的内存走势图,但是也能看出内存一直在增加,不知道为什么我的内存分配Allocations一直为0,希望看到的小伙伴留言解答一下。
上面的代码有三个问题:
1、不断创建String对象,如下代码
paint.setColor(Color.parseColor(color[0]));
点击进去看源码:
public static int parseColor(@Size(min=1) String colorString) {
if (colorString.charAt(0) == ‘#’) {
// Use a long to avoid rollovers on #ffXXXXXX
// 这里调用了String类的substring方法
long color = Long.parseLong(colorString.substring(1), 16);
if (colorString.length() == 7) {
// Set the alpha value
color |= 0x00000000ff000000;
} else if (colorString.length() != 9) {
throw new IllegalArgumentException(“Unknown color”);
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://img-blog.csdnimg.cn/img_convert/2f7ede15da750b794d1c5d46b65a361e.jpeg)
尾声
开发是需要一定的基础的,我是08年开始进入Android这行的,在这期间经历了Android的鼎盛时期,和所谓的Android”凉了“。中间当然也有着,不可说的心酸,看着身边朋友,同事一个个转前端,换行业,其实当时我的心也有过犹豫,但是我还是坚持下来了,这次的疫情就是一个好的机会,大浪淘沙,优胜劣汰。再等等,说不定下一个黄金浪潮就被你等到了。
- 330页 PDF Android核心笔记
- 几十套阿里 、字节跳动、腾讯、华为、美团等公司2020年的面试题
- PDF和思维脑图,包含知识脉络 + 诸多细节
- Android进阶系统学习视频
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
浪潮就被你等到了。
- 330页 PDF Android核心笔记
[外链图片转存中…(img-5LyzAmEa-1711942579200)]
- 几十套阿里 、字节跳动、腾讯、华为、美团等公司2020年的面试题
[外链图片转存中…(img-yD5L1xnw-1711942579200)]
[外链图片转存中…(img-UEkZxY7w-1711942579200)]
- PDF和思维脑图,包含知识脉络 + 诸多细节
[外链图片转存中…(img-NPf4QNLn-1711942579200)]
- Android进阶系统学习视频
[外链图片转存中…(img-ZQuK6cvj-1711942579200)]