使用一些大而全的框架,可能上手很快,但很快你就陷入出了问题不知所措,一顿搜索解决问题,但还是不明所以的状态。
当初学习spring的时候有,现在使用nuxt.js也有,nuxt.js支持后台渲染页面和单页面,也规定了一些项目目录结构,开始还是很娱乐的,轻松启动。但遇到问题,虽然是原生的vue,但找的解决方法还是不能应用,就好像用了假Vue一样,理解原理很重要。
就像Vue学习的初期,官方文档也提醒尽量不用cli去创建项目,包括东西太多,很多还是跟打包有关,你既然要学习vue,就应该只学习重点,不然干扰项打扰,不然会影响效果。
最近在做页面间的跳转,其实我的需求很简单,就是一个视频网站,点击后能跳到播放和详情页。用了一些vue的跳转没有成功,后面使用了nuxt.js推荐的 标签,可以跳转了,而且这个标签还支持传参数。
看到编译后的标签,是一个a标签,然后看文档,这个支持前进和后退功能,相当于自己做了一个浏览器的堆栈保存访问的地址。
现在还有一个问题,就是我想做 播放页点击其他视频,再重新加载,但由于是同一个页面导致不能加载,还没有方法解决。

题目

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。
  • Front: 从队首获取元素。如果队列为空,返回 -1 。
  • Rear: 获取队尾元素。如果队列为空,返回 -1 。
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  • isEmpty(): 检查循环队列是否为空。
  • isFull(): 检查循环队列是否已满。
    示例:
    MyCircularQueue circularQueue = new MycircularQueue(3); // 设置长度为 3
    circularQueue.enQueue(1); // 返回 true
    circularQueue.enQueue(2); // 返回 true
    circularQueue.enQueue(3); // 返回 true
    circularQueue.enQueue(4); // 返回 false,队列已满
    circularQueue.Rear(); // 返回 3
    circularQueue.isFull(); // 返回 true
    circularQueue.deQueue(); // 返回 true
    circularQueue.enQueue(4); // 返回 true
    circularQueue.Rear(); // 返回 4
    提示:
  • 所有的值都在 0 至 1000 的范围内;
  • 操作数将在 1 至 1000 的范围内;
  • 请不要使用内置的队列库。

原题目地址:https://leetcode-cn.com/problems/design-circular-queue/submissions/

思考思路

队列实现有2种选择,一种是数组实现,一种是链表实现。
这个题目长度是固定的,用数组实现更合适。

解题过程

解法1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
class MyCircularQueue {
private int head;
private int tail;
private int size;
private int currentSize;
int[] queue;
//顺序队列

/** Initialize your data structure here. Set the size of the queue to be k. */
public MyCircularQueue(int k) {
this.size = k;
queue = new int[size];
head = 0;
tail = 0;
currentSize = 0;
}

/** Insert an element into the circular queue. Return true if the operation is successful. */
public boolean enQueue(int value) {
if(currentSize == size){
return false;
}
if(currentSize == 0){
head = (head+1)%size;
}
tail = (tail+1)%size;

queue[tail] = value;
currentSize++;
return true;

}
/** Delete an element from the circular queue. Return true if the operation is successful. */
public boolean deQueue() {
if(currentSize == 0){
return false;
}

currentSize--;
if(currentSize != 0){
head = (head + 1)%size;
}
return true;
}

/** Get the front item from the queue. */
public int Front() {
if(currentSize == 0){
return -1;
}
return queue[head];
}

/** Get the last item from the queue. */
public int Rear() {
if(currentSize== 0){
return -1;
}
return queue[tail];

}
/** Checks whether the circular queue is empty or not. */
public boolean isEmpty() {
if(currentSize == 0){
return true;
}
return false;

}

/** Checks whether the circular queue is full or not. */
public boolean isFull() {
if(currentSize == size){
return true;
}
return false;
}
}

总结

思路1,head头指针,tail尾指针,size数组整个大小,currentSize当前数组大小,用于判断边界条件。
head和tail都是真的有数据位,isFull和ieEmpty根据currentSize判断即可,rear直接去tail,font直接取头。
循环存值的方法,就是(当前值+1)%数组长度,保证数组到头,可以从头再来 。
难点在enqueue和dequeue
enqueue时,通过currentSize==size判断是不是队列满了,其实可以调用isFull,没有想到功能的复用。
正常情况,压数据入队列尾,数据存在tail+1的位置,currentSize+1
特殊情况,队列是空的情况,head,tail同时后移1位,这种处理后面发现会浪费一个空间,当时没想到。
dequeue,先判断是不是空队列
正常情况,head+1跟size取余
如果currentSize==0,则什么都不多,防止指针变成负值
总结
难点1,如果保证存储数组可以循环
难点2,队列是空的是,头尾指针的判断

解法2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class MyCircularQueue {
private Integer[] queue;
private int head;
private int tail;
/** Initialize your data structure here. Set the size of the queue to be k. */
public MyCircularQueue(int k) {
queue = new Integer[k];
head = 0;
tail = 0;
}

/** Insert an element into the circular queue. Return true if the operation is successful. */
public boolean enQueue(int value) {
if(isFull()){
return false;
}
queue[tail] = value;
tail = (tail + 1) % queue.length;
return true;
}

/** Delete an element from the circular queue. Return true if the operation is successful. */
public boolean deQueue() {
if(isEmpty()){
return false;
}
queue[head] = null;
head = (head + 1) % queue.length;
return true;
}

/** Get the front item from the queue. */
public int Front() {
if(isEmpty()){
return -1;
}
return queue[head];
}

/** Get the last item from the queue. */
public int Rear() {
if(isEmpty()){
return -1;
}
if(tail!=0)return queue[tail-1];
else return queue[queue.length-1];
}

/** Checks whether the circular queue is empty or not. */
public boolean isEmpty() {
if(tail == head && queue[tail] == null){
return true;
}
return false;
}
/** Checks whether the circular queue is full or not. */
public boolean isFull() {
if(head == tail && queue[tail] != null){
return true;
}
return false;
}
}
/**
* Your MyCircularQueue object will be instantiated and called as such:
* MyCircularQueue obj = new MyCircularQueue(k);
* boolean param_1 = obj.enQueue(value);
* boolean param_2 = obj.deQueue();
* int param_3 = obj.Front();
* int param_4 = obj.Rear();
* boolean param_5 = obj.isEmpty();
* boolean param_6 = obj.isFull();
*/

总结

思路2,看别人的分享有的思路
只需要头,尾指针,和数组
head指针存有数据,tail是最后一个有数据的位的下一个,是一个空指针
队列满,用tail==head,tail!=null,
队列空,tail== head,tail ==null
满或空的都是通过,头尾指针重合,如果尾指针是不是空来判断,这样要保证数据可以存空值
deQueue和deQueue都比较好处理,不用判断特殊的条件
rear要取前一个值,这个要特殊注意。
总结
难点1,通过tail指针指向空的下一个位,来让队列的满或空,很好判断,不会出现特殊位置的判断,很巧妙

第一遍看这部纪录片,纪录片分别从英国找到一群不同阶层的孩子,从7岁开始,每隔7年采访,看这些人的成长与变化。
片子是按时间顺序,我们横向对比,
第一点教育很重要,穷人家的孩子都不太重视教育,没有眼界,不清楚怎么规划未来,有的连大学是什么都不知道,自然比别人要慢很多,或者生活格局要低很多。Nick一个害羞的男孩,通过考取牛津,成功翻身。
第二点,父母、家庭对孩子影响很大,片中paul从小就父母离婚在福利院长大,缺乏自信,一生都会怀疑自己,幸好娶了一个积极的老婆。Symon来自单亲家庭,缺少父爱,很小就比较迷茫。Suzy在14岁,父母离婚,对她打击很大,对婚姻失去希望。
第三点,大部门人都经历了离婚,越晚结婚,婚姻越稳定,婚姻很大程度影响一个人。
第四点,癌症的发病率很高,在那个时候的英国,很多人的父母都是死于癌症,越到老越能体会,身体健康是最重要的。
第五点,片子的立意在于说明英国存在阶级,对于里面的每个人的报道有些节选,不能代表全部,富人区的孩子成功与自身的奋斗也是离不开,穷人区的人穷,有些自己说自己很懒。阶级是客观存在的,但自身努力是可以突破的,但自身努力不代表能完成一切。

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

算法思路:
一个总和链表,一个头指针,一个当前指针,比较原来两个链表哪个小,小的就加到当前链表后面,
如果一个链表结束了,就将另外一个链表后面添加进来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode newList = new ListNode(0);
ListNode current = newList;
while(l1 != null && l2 != null){
int one = l1.val;
int two = l2.val;
if(one <= two ){
current.next = l1;
l1 = l1.next;
current = current.next;

}else{
current.next = l2;
l2 = l2.next;
current = current.next;
}
}
if(l1 != null){
current.next = l1;
}

if(l2 != null){
current.next = l2;
}
return newList.next;
}

}

原版文章 [https://www.aosabook.org/en/distsys.html]

文章主要分为3个部分,讲了可扩展的分布式系统的设计方法。

网络分布式系统的设计原则

6个提到的主要原则
availablity,(可用性):对于一些电商等网站,只要有一阵不能访问,就会损失很多收益,保证可用性很重要。
performance,(性能):保证访问性能,让用户体验更好。
reliablity,(可靠性):保证每个请求都有返回。
scalability,(可扩展性):如果有大流量能保证可以方便的扩展性能。
managebility,(管理性):要易于管理,不然这块成本也很高。
cost,(费用):分布式本身需要很多机器,这块的成本也要考虑。

基础

基础的分布式设计方法,
services,(服务化)
redundancy,(冗余)
partitions,(分区)
handling failure,(处理错误)
举了一个例子,图片网盘,用户可以上传图片,然后读取图片。
首先服务化,将读与写的服务,分开单独优化,因为两边优化的方式不同。
然后冗余处理,将存储的数据,冗余备份,服务冗余。
然后将数据分区,读取不同分区的数据,减少单个的压力。

快速可扩展的数据访问块

这块主要将如何加快数据的访问,5个方面
Caches,global cache,Distributed Cache,
proxies,
Indexes,
load balancers,
queues,
首先是缓存,这个还分为,本地缓存,全局缓存,分布式缓存。
第二部分是代理,这个可以重定向请求。
第三个是索引,类似数据库索引,可以加快数据的访问。
第四个是负载均衡,可以分散请求的压力
第五个是消息队列,可以异步处理,将每个单独调用的任务执行,解耦到消息队列里面,慢慢处理,压力不在后端。

生活中谈反馈延迟

昨天去经常去的,之前储值的理发店,本来是十分不想去的,但想到还有20元在里面,正好这次剪完就不去了,经过一番斗争还是去了。
进去之后,先是干洗,一个小哥,看起来挺年轻的,不紧不慢,不知道是不是新手,最后水洗的时候,说要帮我冲一下眼睛,冲眼睛确实挺舒服的,我想着也别全程不说话,以前我尽量不跟他们搭话,搞的比较熟了,就跟你推销没完没了。我站在他们的角度想想,如果每个顾客都没有反馈,即使做的比较好,也不知道自己做的怎么样,多做还比较累,也没有任何收获,那就糊弄糊弄就好了。所以逐渐越来越消极。有点像平时的生活工作。
反过来一对比,也许生活就是这样的,对于你的努力,收益本身就是有延迟的,大家都努力过,但没有任何反馈,逐渐大家放弃了,得过且过吧。还有一点,你只比别人好一点点,是没有效果的,大家很难发现,你要好就好一大块。
总结来说,就是生活中延迟反馈,加上长板优势。

后面发型师来剪头发,女发型师,没戴眼镜没看出是谁。问了我想要什么发型,我说剪短一点,两边打薄,不要推上去。但她好像没怎么听我的意见,只是跟我确认了一下上边要不要剪短,就开始剪,上来就把两边推了,电推子贴到头皮上,我就感觉她没理解我什么意思。剪的过程确实很认真,技术我也不否定,但给我一种迷之自信,你要求什么不重要,我觉得这样最好了。我突然觉得,这有点像演员,有些演员演什么都像他自己,有些演员演什么像什么。 我不想剪两边的原因是之前剪过,会显得脸特别胖,但她迷之自信,没有理会我的要求,觉得这样更好看,更适合我。
如果她能问问原因,再跟我讨论一下,她想那么剪的原因,我也不是不能接受,但剪完,她觉得自己很优秀,作品很完美。但在我这开头就错了,虽然她在那个理发店已经是总监了,我下次可能再也不会找她剪了。我回来跟女朋友聊了这个事,她也说了这个理发师的事,之前就推荐我女朋友剪空气刘海,然后我女朋友反对后,她还是给剪了空气刘海,真的是醉醉的,我们对她的迷之自信都是佩服。
生活中这样的事情很多,尤其是在专业人士身上。那天去看病,排队在自动挂号收费机,前一个人,缴费之后,界面直接弹框提示一个数据的报错,然后没有打印凭条,问了旁边的工作人员,她一口咬定是刚才那个人直接点返回了,没有打印,这个估计是数据的报错导致的异常,但顾客看不懂那个提示,无法清楚的描述过程和无法及时保留证据,工作人员只能用一个最简单的方式推测他的行为,怪在提出问的人身上,解决不了问题,解决提问题的人。我生活中遇到过很多次这样的问题,现场报上来错误,但是没有证据,我们也不能推测错误原因,那就都怪在提出问题的人,瞎操作。
这个可能的原因之一,太多无法跟踪的问题,你的时间有限,没法一条条都查清楚,找一个简单的理由推脱掉。这样确实会隐藏大问题。

一个人在生活中要自驱动,有目标,有进阶意识,也能开放心态,听进去别人的建议

最近使用puppeteer模拟用户操作,填了不少的坑,写出来分享一下。

puppeteer包

使用npm i puppeteer来下载puppeteer的时候,会自动下载依赖的chromium,但因为众所周知的原因,很难下载,那能不能先下载好再直接引入呢,也可以移植使用。

官方提供2个包一个puppeteer,另外一个是puppeteer-core。puppeteer-core不会自动下载chromium,以及PUPPETEER_* 环境变了都不起效。这个就是我们想要的包。官方提供两个包的差别puppeteer vs puppeteer-core

执行npm i puppeteer-core
下面是使用的代码

1
2
3
4
5
6
7
8
9
10
11
12
const puppeteer = require('puppeteer-core');
async () => {
const browserPath = '../../../chrome-mac/Chromium.app/Contents/MacOS/Chromium'
const browser = await puppeteer.launch(
{
headless: false,
slowMo: 250,
devtools: true,
executablePath: browserPath,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
}

其中一个我遇到比较大的容易错的地方就是executablePath是一个相对地址,当时怎么执行都不行,因为写了一个绝对路径。
这里mac的Chromium要指向Chromium.app/Contents/MacOS/Chromium,也是很容易出错。

Chromium版本

我还遇到一个问题,如果不同操作系统的部署nodejs,网络情况不能自动下载chromium,我随便系统找个版本是不是就行了?
我也试过了,我本来想在树莓派上部署,但树莓派的linux是32位的,上面的chromium也是很长时间之前的的,花了很长时间搞环境,发现不支持puppeteer,每个版本的puppeteer需要绑定版本的chromium,当时真的很崩溃,所以我决定提前下好chromium,按版本放到不同系统里,这样就统一的chromium版本,不会出现不见兼容的问题。
chromium版本查看package.json里的

1
2
3
"puppeteer": {
"chromium_revision": "609904"
},

这个里面就是依赖的版本号。然后去chromium发布库,输入版本号‘609904’,去搜索,这个网站很慢,会从第一个版本一点点搜索,我看了一下请求,每个请求100个数组,一点点遍历数据。
下载好不同系统的同一个版本的chromium后,通过上面的executablePath参数来引入chromium运行。不同操作系统的运行程序不太一样,需要找到对应的执行文件。

采集参数范围

  1. java_buffer_pool
  2. java_class_loading
  3. java_garbage_collector
  4. java_memory
  5. java_runtime
  6. java_system
  7. java_thread

具体参数示意

参数都是通过Mbean获取,可以根据java官方文档获取值,或者自定义。

name: java_buffer_pool

fieldKey | fieldType
Count | float
MemoryUsed | float
TotalCapacity | float

参数区别官方文档:[https://docs.oracle.com/javase/7/docs/api/java/lang/management/BufferPoolMXBean.html]

MemoryUsed是返回虚拟机用于缓冲池用于内存的估计值。
Count是返回池中缓冲区数的估计值。
TotalCapacity是返回池中缓冲区总量的估计值。

其中有2个tag的key,”mapped buffer pool” and “direct buffer pool”,
Stackoverflow的解释[https://stackoverflow.com/questions/15657837/what-is-mapped-buffer-pool-direct-buffer-pool-and-how-to-increase-their-size]
direct buffer pool是Java与系统io子系统交互的内存区,比如disk读写或者收到socket请求,直接用更快。
mapped buffer pool是java FileChannel 实例使用的。

name: java_class_loading

fieldKey | fieldType
LoadedClassCount | float
TotalLoadedClassCount | float
UnloadedClassCount | float

官方文档:[https://docs.oracle.com/javase/7/docs/api/java/lang/management/ClassLoadingMXBean.html]

LoadedClassCount返回当前虚拟机中加载类的数量。
TotalLoadedClassCount返回虚拟机开始执行以来已加载的类的数量。
UnloadedClassCount返回虚拟机开始执行以来卸载的类的数量。

name:java_garbage_collector

fieldKey | fieldType
CollectionCount | float
CollectionTime | float
官方文档:[https://docs.oracle.com/javase/7/docs/api/java/lang/management/GarbageCollectorMXBean.html]
CollectionCount已经进行的垃圾回收的次数
CollectionTime返回累计的垃圾回收时间(以毫秒为单位)

name: java_memory

fieldKey | fieldType
HeapMemoryUsage.committed | float
HeapMemoryUsage.init | float
HeapMemoryUsage.max | float
HeapMemoryUsage.used | float
NonHeapMemoryUsage.committed | float
NonHeapMemoryUsage.init | float
NonHeapMemoryUsage.max | float
NonHeapMemoryUsage.used | float
ObjectPendingFinalizationCount | float

官方文档:[https://docs.oracle.com/javase/7/docs/api/java/lang/management/MemoryMXBean.html]

HeapMemory和NonHeapMemory的区别
1.堆
Java虚拟机有一个堆,它是运行时数据区,从中分配所有类实例和数组的内存。它是在Java虚拟机启动时创建的。对象的堆内存由自动内存管理系统回收,该系统 为垃圾收集器。
堆可以是固定大小的,也可以是扩展和收缩的。堆的内存不需要是连续的。

2.非堆内存
Java虚拟机管理堆以外的内存(称为非堆内存)。
Java虚拟机具有在所有线程之间共享的方法区域。方法区域属于非堆内存。它存储每类结构,例如运行时常量池,字段和方法数据,以及方法和构造函数的代码。它是在Java虚拟机启动时创建的。

方法区域在逻辑上是堆的一部分,但Java虚拟机实现可以选择不垃圾收集或压缩它。与堆类似,方法区域可以是固定大小的,也可以是扩展和收缩的。方法区域的内存不需要是连续的。

除了方法区域之外,Java虚拟机实现可能需要用于内部处理或优化的存储器,其也属于非堆存储器。例如,JIT编译器需要用于存储从Java虚拟机代码转换的本机机器代码的存储器以获得高性能。

MemoryUsage 官方文档[ https://docs.oracle.com/javase/7/docs/api/java/lang/management/MemoryUsage.html ]

MemoryUsage对象包含四个值:

  • init表示Java虚拟机在启动期间从操作系统请求内存管理的初始内存量(以字节为单位)。 Java虚拟机可以从操作系统请求额外的内存,并且还可以随时间向系统释放内存。 init的值可能未定义。
  • used表示当前使用的内存量(以字节为单位)。
  • committed表示保证可供Java虚拟机使用的内存量(以字节为单位)。提交的内存量可能会随着时间的推移而变化(增加或减少)。 Java虚拟机可能会向系统释放内存,并且已提交的内存可能少于init。已提交将始终大于或等于使用。
  • max表示可用于内存管理的最大内存量(以字节为单位)。它的价值可能是不确定的。如果已定义,最大内存量可能会随时间而变化。如果定义了max,则使用和提交的内存量将始终小于或等于max。如果内存分配尝试增加已使用的内存,则可能会失败,即使已使用>已提交<= max仍然为真(例如,当系统虚拟内存不足时)。
+----------------------------------------------+
+////////////////           |                  +
+////////////////           |                  +
+----------------------------------------------+

|--------|
   init
|---------------|
       used
|---------------------------|
          committed
|----------------------------------------------|
                    max

name: java_memory_pool

fieldKey | fieldType
CollectionUsage.committed | float
CollectionUsage.init | float
CollectionUsage.max | float
CollectionUsage.used | float
PeakUsage.committed | float
PeakUsage.init | float
PeakUsage.max | float
PeakUsage.used | float
Usage.committed | float
Usage.init | float
Usage.max | float
Usage.used | float

  1. Memory Usage
    getUsage()方法提供对内存池当前使用情况的估计。 对于垃圾收集的内存池,已用内存量包括池中所有对象占用的内存,包括可访问和不可访问的对象。
    通常,此方法是一种轻量级操作,用于获取大致的内存使用量。 对于某些内存池,例如,当对象未连续打包时,此方法可能是一项昂贵的操作,需要一些计算来确定当前的内存使用情况。 在这种情况下,实现应该记录。

  2. Peak Memory Usage
    自虚拟机启动或重置峰值以来,Java虚拟机维护内存池的峰值内存使用量。 峰值内存使用量由getPeakUsage()方法返回,并通过调用resetPeakUsage()方法重置。

  3. Usage Threshold
    每个内存池都有一个称为使用阈值的可管理属性,该属性具有Java虚拟机提供的默认值。默认值取决于平台。可以通过setUsageThreshold方法设置使用率阈值。如果阈值设置为正值,则在此内存池中启用使用阈值交叉检查。如果使用阈值设置为零,则禁用对此内存池的使用率阈值交叉检查。 isUsageThresholdSupported()方法可用于确定是否支持此功能。
    Java虚拟机在其最佳适当时间(通常在垃圾收集时)执行基于内存池的使用阈值交叉检查。每个内存池都维护一个使用阈值计数,当Java虚拟机检测到内存池使用率超过阈值时,该计数将逐渐增加。

此可管理的使用阈值属性旨在以较低的开销监视内存使用量的增加趋势。使用率阈值可能不适合某些内存池。例如,世代垃圾收集器(在许多Java虚拟机实现中使用的常见垃圾收集算法)管理两个或更多代按年龄隔离对象。大多数对象都分配在最年轻的一代(比如一个托儿所内存池)。托儿所内存池旨在填充并收集托儿所内存池将释放其大部分内存空间,因为它预计包含大多数短期对象,并且大部分在垃圾收集时无法访问。在这种情况下,托儿所内存池更不适合不支持使用阈值。此外,如果一个内存池中的对象分配成本非常低(例如,只是原子指针交换),那么Java虚拟机可能不会支持该内存池的使用率阈值,因为在比较使用情况时的开销是阈值高于对象分配的成本。

  1. Collection Usage Threshold
    垃圾回收阈值是一个可管理的属性,仅适用于某些垃圾收集的内存池。在Java虚拟机通过在垃圾收集时回收内存池中的未使用对象来花费回收内存空间之后,收集的内存池中的一些字节仍将被使用。集合使用阈值允许为此字节数设置一个值,以便在超过阈值时,MemoryMXBean将发出超出集合使用阈值的通知。此外,收集使用阈值计数将增加。

name: java_runtime

fieldKey | fieldType
StartTime | float
Uptime | float

官方文档 [https://docs.oracle.com/javase/7/docs/api/java/lang/management/RuntimeMXBean.html]

Uptime是java虚拟机启动的时间(以毫秒为单位),StartTime是java虚拟机最开始开启的时间(以毫秒为单位)

name: java_system

fieldKey | fieldType
ProcessCpuLoad | float
SystemCpuLoad | float
TotalPhysicalMemorySize | float

官方文档 [[]https://docs.oracle.com/javase/7/docs/api/java/lang/management/OperatingSystemMXBean.html]
SystemCpuLoad返回系统每分钟的负载。系统负载平均值是排队到可用处理器的可运行实体数量与在一段时间内平均可用处理器上运行的可运行实体数量之和。 计算负载平均值的方式是特定于操作系统,但通常是与时间相关的阻尼。
其他参数未找到。

name: java_thread

fieldKey | fieldType
DaemonThreadCount | float
PeakThreadCount | float
ThreadCount | float
TotalStartedThreadCount | float
官方文档 [https://docs.oracle.com/javase/7/docs/api/java/lang/management/ThreadMXBean.html]

DaemonThreadCount 返回当前活动守护程序线程的数量。
PeakThreadCount 返回自Java虚拟机启动或峰值重置以来的峰值活动线程数。
ThreadCount 返回当前活动线程数,包括守护程序和非守护程序线程。
TotalStartedThreadCount 返回自Java虚拟机启动以来创建和启动的线程总数。

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

最近在反思自己的学习方法,总感觉自己好像缺少一些东西,虽然表面上一直自认为很努力的样子,但没有什么效果,表面上用了很多时间,但并没有什么实际产出,想回头看看之前斯考特·杨写得《如何高效学习》,看着看着又想起之前自己看过的在缓慢思考公众号里戴汩提到的费曼方法。

费曼技术

费曼方法很简单,总共3步,

  1. 教给孩子
    先用一张纸,写下你要讲解的概念,然后试图讲给一个8岁的孩子,而不是一个成年人,不要用术语,而是用简单朴素的语言。人们经常被复杂的术语和概念迷惑,使用术语而忽视实际是否已经掌握。
  2. 回顾
    看看哪个地方没有讲通,那个就是你知识的边界,回到原始资料,重新学习你不会的概念
  3. 组织和简化
    重新梳理成一个连贯的故事
  4. 发送(可选)
    费曼技术是费曼学习的方法,让你比别人更快更深刻的理解概念和事物,从根本上讲费曼方法是认为智力是可以增长的,这是成长型思维和表现型思维的差异。如何才能比别人了解的都深刻呢,就是放弃复杂的术语和概念,让自己从更基础的方式去思考,复杂的术语和概念容易让人迷糊,以为自己已经懂得了。
    另外还隐藏一个内容就是教是最好的学习,通过教别人,让自己也理清关系。

总结起来包括两个,一:教是最好的学习方法,二:通过降低对方的知识水平倒逼自己理解清楚整个概念,从最基础的概念入手,弄清楚所有的知识脉络。

费曼技术有点像一种检验的方法,从反面去检查自己是否把知识学明白,还能找到自己哪个点没有学明白,这个很厉害。

整体性学习法

这个分为获取,理解,拓展,修正,应用,测试。整体性学习方法基础是认为大脑更好的记忆方式是通过知识的连接,而不是像计算机一样的复制就能处理信息。这一点可能还不能用科学方式完全证明,所以这套理论还停留在理论阶段,但这个就像冥想一样虽然早些时候还没有科学的方法证明,但它的方法却实实在在的有效,所以大家都在实践。这套理论也是作者根据自身的作为总结的。

既然大脑记忆知识的方法通过不断连接更有效的记忆,那我们就要从这个角度下手去梳理知识,让记忆的存储更高效的提取,如果提取的方式都是混乱的,那很难提取就不是没有道理的。整体学习法的存储方式是通过方式

  1. 结构:知识的大厦
    结构是知识的全部,你不断的建立大楼来整合知识。
  2. 模型:结构的种子
    模型是结构的缩影,归根结底是信息的压缩,将核心的概念进行缩减,构建一个小型结构,对于学习新的概念作用很大。
  3. 高速公路:连接结构和模型
    哪种知识更容易提取,是四通八达的大楼还是只有一条泥泞小路的喽,连通越多,知识的提取越方便越快捷
    通过以上结构来完善你的知识存储,知识的存储是理解和应用的基础。

理解了存储,那整体学习的框架是什么,整体的流程是怎么样的呢?

  1. 获取:通过各种渠道获得知识
  2. 理解:了解内容的意思
  3. 拓展:扩展知识的内涵和外延
  4. 纠错:修正错误的高速公路
  5. 应用:将知识使用到实际中去
  6. 测试:检验知识的正确性
    作者将整个学习过程,分解成具体的几个步骤,然后每个步骤击破,用具体的技术完善每一个步骤,提高效率,这里先不讲具体的方法,先分清楚每个步骤的意义。
    获取:输入,输入的目标包括:简化,速度,容量。优化输入,让你获取更多的知识,更高效。
    理解:就是明白表面的意义,更快的抓住重点。
    拓展:是处理信息最难的一步,包括深度拓展:背景知识的了解,有助于记忆内容。横向拓展:相关内容的了解,周边知识的理解让你扩展知识面。纵向拓展:这个最具创造性,通过相似性,找到不同大厦之间的高速通道,打破知识的边界,真正连通不同的模型、结构。
    纠错:如果高速公路的连接错误,就纠正错误,让知识间的连接更正确的连接
    应用:信息处理包含3个层次:理解,拓展和应用。到了应用是最好层次,让它在实际生活中有用处,改变生活。
    测试:可以融合在每一步中,检验知识的正确性。我个人认为费曼技巧就是一种相当棒的测试方法,测试你的知识是否理解正确,还能找到哪个地方不足。

实际使用中,一整套框架的顺序是不定的,顺序是可以颠倒的,但要理解整体的流程,每个部分的意义都要体现。整套框架配合费曼技巧,从正反两个方面对知识进行学习、校验,十分实用。