先说一下为啥写文章吧,马上研二了,老师不管我也没好好学习,现在实习也找不到,真是干啥啥
不行,为了不做five,决定开始写文章记录学习,顺带在晚上回顾每天学习的内容,希望能做到日更。
再简单说一下自己目前的目标吧,jvm+各种其他面经弄清楚,刷题top100,写一个网页版斗地主,优化
之前的项目,部署。先这样,希望自己能坚持。
今日总结
看了黑马jvm 1-34
leetcode 做了top 3道简单的
看了一点websocket
JVM
jvm的好处
java的(二进制字节码)运行环境
- 一次编写,到处运行
- 自动内存管理,垃圾回收功能
- 数组下标越界检查
- 底层用虚方法实现多态
内存结构
1 程序计数器
Program Counter Register
Java代码运行流程:
代码-解释器-机器码-cpu
- 作用:记住下一条指令地址
- 特点
- 线程私有
- 不会存在内存溢出
2 虚拟机栈
栈-线程运行需要的内存空间
栈桢-每个方法运行时需要的内存(存参数、局部变量、返回地址)
每个线程只有一个活动栈桢,对应当前正在执行的方法
相关面试题
- 垃圾回收是否设计栈内存?
- 不需要,会自己弹出栈
- 栈内存分配越大越好吗?
- 不是,物理内存时一定的,栈内存越大,线程数就会少了。
- 方法内的局部变量是否线程安全?
- 局部变量是线程私有的线程安全。
- 作为方法参数传递的时候会有线程安全问题(会被共享)。
- 作为方法返回值也有有问题。(会被共享)
- 结论:没有逃离方法的作用访问范围是安全的,局部变量引用对象并逃离作用范围,有线程安全问题。
栈内存溢出
错误名称:java.lang.StackOverflowError
原因:
- 栈桢过多(递归没有结束条件,循环引用一个里面有另一个)
- 栈桢过大
线程运行诊断
- 案例1 : cpu占用过多
- 定位怎么占用
(1): linux 下
top:查看系统占用,看是哪个进程占用过高
ps :看是哪个线程占用过高
ps H -eo pid,tid,%cpu | grep 进程id
(2):用jdk的方法
根据jstack找到有问题的线程,进一步定位到问题的行数
- 案例2 :程序运行很长时间没有结果
jstack+进程id 能看见死锁
3 本地方法栈
native method stacks:用c/c++编写的api
比如: Object的clone()
wait()、hashcode()、wait()、notify()、notifyAll()
4 堆
heap堆:用new 创建的对象使用堆内存
特点:
- 线程共享,需要考虑线程安全问题
- 有垃圾回收机制
堆内存溢出
java.lang.OutOfMemoryError:Java heap space
堆内存诊断
- jps 工具
- 查看系统中有哪些java 进程
- jmap工具
- 查看堆内存占用情况
- jconsole工具
- 连续监测
使用jmap的时候出现问题,
经搜索可能是jdk版本问题,于是改成jdk11
搞错了…再来,要改环境里的mac版本,因为用的是命令行
mac下的操作:
先进入/Library/Java/JavaVirtualMachines
找到版本号名称
vim ~/.bash_profile
修改 JAVA_HOME的版本号
source /etc/profile保存即可
参考https://www.jianshu.com/p/4fd5f6bc6dfb
然后就OK了
但是问题仍然没有解决…
于是使用提示的
…??又出现了一开始的问题,人麻了
权限问题
还是不行…
https://zhuanlan.zhihu.com/p/399352540
刷到一个帖子…还是去年的,也没成功,算了放弃,麻了还是用jconsole
- 案例:垃圾回收之后内存占用仍然很高
先装jvisualVM
https://blog.csdn.net/Tanganling/article/details/119790892
方法区
定义:是所有java虚拟机线程共享的一个区(现在在本地内存上),存储了和类的结构相关的一些信息:运行时常量池、成员变量,方法数据,成员方法,构造器方法以及一些特殊方法。虚拟机启动时创建,在逻辑上是堆的一个组成部分。永久代和元空间是方法区的一个实现。方法区也会内存溢出
内存溢出
- 1.8之前永久代
- 1.8之后元空间
场景:spring和mybatis用cjlib代理动态生成类生成很多运行时的类,永久代垃圾回收比 较差。
常量池
实际上就是一张表,根据这张表找到要执行的类名、方法名、参数类型、字面量等信息。
二进制字节码包括:类基本信息,常量池,类方法定义,虚拟机指令
getstatic:获取静态变量
ldc: 加载一个参数
invokevirtual:执行一次虚方法调用
运行时常量池
一个类运行时要放到内存里,放在内存中的位置就是运行时常量池
StringTable 串池
常量池中的信息都会被加载到运行时常量池,还没变成java字符串对象。
ldc的时候,会把到StringTable里面去找,没有的话会把符号变成字符串对象放进串池。用到的时候才区创建(懒加载)。
StringTable是一个hashtable的结构,不能扩容。
- 拼接
String s3 = s1+s2 ;
创建一个新的StringBuilder并调用构造方法。
s3是串池中的,s4是new的,所以false
s5是看拼接后的值(在编译器拼接的,因为都是常量,之前的s1,s2都是常量)串池中是否有,所以是true。
动态拼接的元素不会存在串池中,像下面这种,”a“和"b"会出现在串池中,"ab"不会存在串池中(动态拼接),会放到堆里,只有常量才会放进去
调用s.intern()方法会尝试放入串池,并把串池中的对象返回
两个都是true,因为都是同一个
上ture:因为都是从常量池取出来的
下false:s那个是new出来的
Leetcode
461 汉明距离
直接用了循环,每次和1与就可以了
338 比特位计数
- 用循环,复杂度太高
- 动态规划,只有最后一位不一样,所以看 右移一位(已经存在)+最后一位是否有变化
215 数组中的第K个最大元素
是个排序题,自己看文章准备自己实现手动,结果发现还挺有难度,之前学的全忘了,而且理论和实践也是两码事,目前才写了5个简单的,明天一起总结吧。
最后想说
今天学了很长时间,可能和考研时候差不多了,因为真的突然感受到自己的无能为力,希望能坚持!!