Paul Jiang's Blog

  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

机器学习-项目

发表于 2018-11-18 | 更新于 2020-05-17 | 分类于 机器学习

项目地址

https://github.com/pauljoo/labs-ml

一个完整机器学习项目的主要步骤

  1. 项目概述。
  2. 获取数据。
  3. 发现并可视化数据,发现规律。
  4. 为机器学习算法准备数据。
  5. 选择模型,进行训练。
  6. 微调模型。
  7. 给出解决方案。
  8. 部署、监控、维护系统。

数据来源

  • 流行的开源数据仓库:
    • UC Irvine Machine Learning Repository
    • Kaggle datasets
    • Amazon’s AWS datasets
  • 准入口(提供开源数据列表)
    • http://dataportals.org/
    • http://opendatamonitor.eu/
    • http://quandl.com/
  • 其它列出流行开源数据仓库的网页:
    • Wikipedia’s list of Machine Learning datasets
    • Quora.com question
    • Datasets subreddit

项目概述

利用加州普查数据,建立一个加州房价模型。这个数据包含每个街区组的人口、收入中位数、房价中位数等指标

划定问题

首先,你需要划定问题:监督或非监督,还是强化学习?这是个分类任务、回归任务,还是其它的?要使用批量学习还是线上学习?

  1. 问老板的第一个问题应该是商业目标是什么?
    建立模型可能不是最终目标。公司要如何使用、并从模型受益?
    这非常重要,因为它决定了如何划定问题,要选择什么算法,评估模型性能的指标是什么,要花多少精力进行微调。
    老板告诉你你的模型的输出(一个区的房价中位数) 会传给另一个机器学习系统,也有其它信号会传入后面的系统。
    这一整套系统可以确定某个区进行投资值不值。确定值不值得投资非常重要,它直接影响利润。

  2. 现在的解决方案效果如何

老板通常会给一个参考性能,以及如何解决问题。
老板说,现在街区的房价是靠专家手工估计的,专家队伍收集最新的关于一个区的信息(不包括房价中位数) ,他们使用复杂的规则进行估计。
这种方法费钱费时间,而且估计结果不理想,误差率大概有 15%。

选择性能指标

回归问题的典型指标是均方根误差(RMSE)。均方根误差测量的是系统预测误差的标准差。

虽然大多数时候 RMSE 是回归任务可靠的性能指标,在有些情况下,你可能需要另外的函数。
例如,假设存在许多异常的街区。此时,你可能需要使用平均绝对误差(Mean Absolute Error,也称作平均绝对偏差) ,

RMSE 和 MAE 都是测量预测值和目标值两个向量距离的方法。

核实假设

最后,最好列出并核对迄今(你或其他人) 作出的假设,这样可以尽早发现严重的问题。

例如,你的系统输出的街区房价,会传入到下游的机器学习系统,我们假设这些价格确实会被当做街区房价使用。
但是如果下游系统实际上将价格转化成了分类(例如,便宜、中等、昂贵) ,然后使用这些分类,而不是使用价格。
这样的话,获得准确的价格就不那么重要了,你只需要得到合适的分类。
问题相应地就变成了一个分类问题,而不是回归任务。你可不想在一个回归系统上工作了数月,最后才发现真相。

获取数据

1
conda install jupyter matplotlib numpy pandas scipy scikit-learn

创建工作空间

1
jupyter notebook --ip=0.0.0.0 --no-browser --allow-root

创建测试集

在这个阶段就分割数据,听起来很奇怪。毕竟,你只是简单快速地查看了数据而已,你需要再仔细调查下数据以决定使用什么算法。

这么想是对的,但是人类的大脑是一个神奇的发现规律的系统,这意味着大脑非常容易发生过拟合:

如果你查看了测试集,就会不经意地按照测试集中的规律来选择某个特定的机器学习模型。
再当你使用测试集来评估误差率时,就会导致评估过于乐观,而实际部署的系统表现就会差。这称为数据透视偏差。

  1. 纯随机的取样方法
    当你的数据集很大时(尤其是和属性数相比) ,这通常可行;但如果数据集不大,就会有采样偏差的风险。
  2. 分层采样
    将人群分成均匀的子分组,称为分层,从每个分层去取合适数量的实例,以保证测试集对总人数有代表性。

数据探索和可视化、发现规律

前为止,你只是快速查看了数据,对要处理的数据有了整体了解。现在的目标是更深的探索数据。
首先,保证你将测试集放在了一旁,只是研究训练集。

地理数据可视化

通常来讲,人类的大脑非常善于发现图片中的规律,但是需要调整可视化参数使规律显现出来。

1
housing.plot(kind="scatter", x="longitude", y="latitude", alpha=0.1)

查找关联

当数据集并不是非常大,可以很容易地使用 corr() 方法计算出每对属性间的标准相关系数(standard correlation coefficient,也称作皮尔逊相关系数)

相关系数的范围是 -1 到 1。

  • 当接近 1 时,意味强正相关;例如,当收入中位数增加时,房价中位数也会增加。
  • 当相关系数接近 -1 时,意味强负相关;
  • 相关系数接近 0,意味没有线性相关性。

警告:相关系数只测量线性关系(如果 x 上升, y 则上升或下降)。
相关系数可能会完全忽略非线性关系(例如,如果 x 接近 0,则 y 值会变高)。

1
2
corr_matrix = housing.corr()
corr_matrix["median_house_value"].sort_values(ascending=False)

scatter_matrix

另一种检测属性间相关系数的方法是使用 Pandas 的 scatter_matrix 函数,它能画出每个数值属性对每个其它数值属性的图。

1
2
3
from pandas.tools.plotting import scatter_matrix
attributes = ["median_house_value", "median_income", "total_rooms","housing_median_age"]
scatter_matrix(housing[attributes], figsize=(12, 8))

最有希望用来预测房价中位数的属性是收入中位数,因此将这张图放大

1
housing.plot(kind="scatter", x="median_income",y="median_house_value",alpha=0.1)

你发现了一些数据的巧合,需要在给算法提供数据之前,将其去除。
你还发现了一些属性间有趣的关联,特别是目标属性。
你还注意到一些属性具有长尾分布,因此你可能要将其进行转换(例如,计算其 log 对数)。
当然,不同项目的处理方法各不相同,但大体思路是相似的。

属性组合试验

给算法准备数据之前,你需要做的最后一件事是尝试多种属性组合。
例如,如果你不知道某个街区有多少户,该街区的总房间数就没什么用。
你真正需要的是每户有几个房间。
相似的,总卧室数也不重要:你可能需要将其与房间数进行比较。
每户的人口数也是一个有趣的属性组合。

1
2
3
4
5
housing["rooms_per_household"] = housing["total_rooms"]/housing["households"]
housing["bedrooms_per_room"] = housing["total_bedrooms"]/housing["total_rooms"]
housing["population_per_household"]=housing["population"]/housing["households"]
corr_matrix = housing.corr()
corr_matrix["median_house_value"].sort_values(ascending=False)

看起来不错!与总房间数或卧室数相比,新的 bedrooms_per_room 属性与房价中位数的关联更强。
显然,卧室数/总房间数的比例越低,房价就越高。
每户的房间数也比街区的总房间数的更有信息,很明显,房屋越大,房价就越高。

为机器学习算法准备数据

数据清洗

大多机器学习算法不能处理缺失的特征,因此先创建一些函数来处理特征缺失的问题。
前面,你应该注意到了属性 total_bedrooms 有一些缺失值。
有三个解决选项:

  • 去掉对应的街区;
  • 去掉整个属性;
  • 进行赋值(0、平均值、中位数等等) 。

处理文本和类别属性

前面,我们丢弃了类别属性 ocean_proximity ,因为它是一个文本属性,不能计算出中位数。
大多数机器学习算法跟喜欢和数字打交道,所以让我们把这些文本标签转换为数字。

自定义转换器

尽管 Scikit-Learn 提供了许多有用的转换器,你还是需要自己动手写转换器执行任务,比如自定义的清理操作,或属性组合。
你需要让自制的转换器与 Scikit-Learn 组件(比如流水线) 无缝衔接工作,因为 Scikit-Learn 是依赖依赖类型的(而不是继承),
你所需要做的是创建一个类并执行三个方法: fit() (返回 self ) , transform() ,和 fit_transform() 。

特征缩放

数据要做的最重要的转换之一是特征缩放。除了个别情况,当输入的数值属性量度不同时,机器学习算法的性能都不会好。
这个规律也适用于房产数据:总房间数分布范围是 6 到39320,而收入中位数只分布在 0 到 15。注意通常情况下我们不需要对目标值进行缩放。
有两种常见的方法可以让所有的属性有相同的量度:线性函数归一化(Min-Max scaling)和标准化(standardization) 。

转换流水线

你已经看到,存在许多数据转换步骤,需要按一定的顺序执行。幸运的是,Scikit-Learn 提供了类 Pipeline ,来进行这一系列的转换。

选择并训练模型

在训练集上训练和评估

线性回归模型

  1. 先来训练一个线性回归模型

    1
    2
    3
    from sklearn.linear_model import LinearRegression
    lin_reg = LinearRegression()
    lin_reg.fit(housing_prepared, housing_labels)
  2. 用训练集评估下

    1
    2
    3
    4
    housing_predictions = lin_reg.predict(housing_prepared)
    lin_mse = mean_squared_error(housing_labels, housing_predictions)
    lin_rmse = np.sqrt(lin_mse)
    lin_rmse

DecisionTreeRegressor

  1. 尝试一个更为复杂的模型 DecisionTreeRegressor
    1
    2
    3
    4
    from sklearn.tree import DecisionTreeRegressor
    tree_reg = DecisionTreeRegressor()
    tree_reg.fit(housing_prepared, housing_labels)
    # 68628.413493824875

大多数街区的 median_housing_values 位于 120000到 265000 美元之间,因此预测误差 68628 美元不能让人满意。
这是一个模型欠拟合训练数据的例子。
当这种情况发生时,意味着特征没有提供足够多的信息来做出一个好的预测,或者模型并不强大。

  1. 用训练集评估下
    1
    2
    3
    4
    5
    housing_predictions = tree_reg.predict(housing_prepared)
    tree_mse = mean_squared_error(housing_labels, housing_predictions)
    tree_rmse = np.sqrt(tree_mse)
    tree_rmse
    # 0.0

没有误差?这个模型可能是绝对完美的吗?当然,更大可能性是这个模型严重过拟合数据。
如何确定呢?如前所述,直到你准备运行一个具备足够信心的模型,都不要碰测试集,因此你需要使用训练集的部分数据来做训练,用一部分来做模型验证。

使用交叉验证做更佳的评估

  1. 用函数 train_test_split 来分割训练集
    评估决策树模型的一种方法是用函数 train_test_split 来分割训练集,得到一个更小的训练
    集和一个验证集,然后用更小的训练集来训练模型,用验证集来评估。这需要一定工作量,
    并不难而且也可行。

  2. 用 Scikit-Learn 的交叉验证功能
    另一种更好的方法是使用 Scikit-Learn 的交叉验证功能。下面的代码采用了 K 折交叉验证(K-fold cross-validation) :
    它随机地将训练集分成十个不同的子集,成为“折”,然后训练评估决策树模型 10 次,每次选一个不用的折来做评估,用其它 9 个来做训练。
    结果是一个包含10 个评分的数组。

判断没错:决策树模型过拟合很严重,它的性能比线性回归模型还差。

RandomForestRegressor

1
2
3
4
5
6
from sklearn.ensemble import RandomForestRegressor
forest_reg = RandomForestRegressor()
forest_reg.fit(housing_prepared, housing_labels)
# [...]
forest_rmse
# 22542.396440343684

随机森林看起来很有希望。但是,训练集的评分仍然比验证集的评分低很多。
解决过拟合可以通过简化模型,给模型加限制(即,规整化) ,或用更多的训练数据。
在深入随机森林之前,你应该尝试下机器学习算法的其它类型模型(不同核心的支持向量机,神经网络,等等),
不要在调节超参数上花费太多时间。目标是列出一个可能模型的列表(两到五个) 。

模型微调

假设你现在有了一个列表,列表里有几个有希望的模型。你现在需要对它们进行微调。

微调的一种方法是手工调整超参数,直到找到一个好的超参数组合。这么做的话会非常冗长,你也可能没有时间探索多种组合。

网格搜索

你应该使用 Scikit-Learn 的 GridSearchCV 来做这项搜索工作。
你所需要做的是告诉 GridSearchCV 要试验有哪些超参数,要试验什么值,GridSearchCV 就能用交叉验证试验所有可能超参数值的组合。

随机搜索

当探索相对较少的组合时,就像前面的例子,网格搜索还可以。但是当超参数的搜索空间很大时,最好使用 RandomizedSearchCV 。

集成方法

另一种微调系统的方法是将表现最好的模型组合起来。
组合(集成) 之后的性能通常要比单独的模型要好(就像随机森林要比单独的决策树要好) ,特别是当单独模型的误差类型不同时。

分析最佳模型和它们的误差

通过分析最佳模型,常常可以获得对问题更深的了解。比如, RandomForestRegressor 可以指出每个属性对于做出准确预测的相对重要性
有了这个信息,你就可以丢弃一些不那么重要的特征(比如,显然只要一个 ocean_proximity 的类型(INLAND) 就够了,所以可以丢弃掉其它的)。
你还应该看一下系统犯的误差,搞清为什么会有些误差,以及如何改正问题(添加更多的特征,或相反,去掉没有什么信息的特征,清洗异常值等等)。

用测试集评估系统

调节完系统之后,你终于有了一个性能足够好的系统。现在就可以用测试集评估最后的模型了。
这个过程没有什么特殊的:从测试集得到预测值和标签,运行 full_pipeline 转换数据(调用 transform() ,而不是 fit_transform() !),再用测试集评估最终模型。

评估结果通常要比交叉验证的效果差一点,如果你之前做过很多超参数微调(因为你的系统在验证集上微调,得到了不错的性能,通常不会在未知的数据集上有同样好的效果)。
这个例子不属于这种情况,但是当发生这种情况时,你一定要忍住不要调节超参数,使测试集的效果变好;这样的提升不能推广到新数据上。
然后就是项目的预上线阶段:你需要展示你的方案(重点说明学到了什么、做了什么、没做什么、做过什么假设、系统的限制是什么,等等),
记录下所有事情,用漂亮的图表和容易记住的表达(比如,“收入中位数是房价最重要的预测量”) 做一次精彩的展示。

启动、监控、维护系统

很好,你被允许启动系统了!你需要为实际生产做好准备,特别是接入输入数据源,并编写测试。

你还需要编写监控代码,以固定间隔检测系统的实时表现,当发生下降时触发报警。这对于捕获突然的系统崩溃和性能下降十分重要。
做监控很常见,是因为模型会随着数据的演化而性能下降,除非模型用新数据定期训练。

  • 评估系统的表现需要对预测值采样并进行评估。
    这通常需要人来分析。分析者可能是领域专家,或者是众包平台(比如 Amazon Mechanical Turk 或 CrowdFlower) 的工人。
    不管采用哪种方法,你都需要将人工评估的流水线植入系统。

  • 你还要评估系统输入数据的质量。
    有时因为低质量的信号(比如失灵的传感器发送随机值,或另一个团队的输出停滞) ,系统的表现会逐渐变差,但可能需要一段时间,系统的表现才能下降到一定程度,触发警报。
    如果监测了系统的输入,你就可能尽量早的发现问题。对于线上学习系统,监测输入数据是非常重要的。

  • 最后,你可能想定期用新数据训练模型。
    你应该尽可能自动化这个过程。如果不这么做,非常有可能你需要每隔至少六个月更新模型,系统的表现就会产生严重波动。
    如果你的系统是一个线上学习系统,你需要定期保存系统状态快照,好能方便地回滚到之前的工作状态。

k近邻算法

发表于 2018-11-18 | 更新于 2020-05-17 | 分类于 机器学习

k-近邻算法(kNN)

描述:采用测量不同特征值之间的距离方法进行分类。

优点:精度高、对异常值不敏感、无数据输入假定。

缺点:计算复杂度高、空间复杂度高。

适用数据范围:数值型和标称型

工作原理:我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个(通常k<20)最相似的数据。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

1.收集数据:可以使用任何方法。

2.准备数据:距离计算所需要的数值,最好是结构化的数据格式。

3.分析数据:可以使用任何方法。

4.训练算法:此步骤不适用于k-近邻算法。

5.测试算法:计算错误率。

6.使用算法:首先需要输入样本数据和结构化的输出结构,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算粗的分类执行后续的处理。

计算向量点的距离:

数值归一化

在处理不同取值范围的特征值时,我们通常采用的方法是将数值归一化,如将取值范围处理为0到1或者-1到1之间。

特征值转化为0到1区间内的值:newValue = (oldValue - min)/ (max - min)

k-近邻算法是分类数据最简单最有效的算法。k-近邻算法是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数据。k-近邻算法必须保存全部数据集,如果训练数据集很大,必须使用大量的存储空间。此外,由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时。

k-近邻算法的另一个缺陷是它无法给出任何数据的基础结构信息,因此我们也无法知晓平均实例样本和典型实例样本具有什么特征。

C++标准程序库-通用工具

发表于 2018-11-16 | 更新于 2020-05-17 | 分类于 语言

Pair和Tuple

Class pair可将两个value视为一个单元。

1
2
3
4
5
6
7
8
9
namespace std
{
template <typename T1, typename T2>
struct pair
{
T1 first;
T2 second;
};
}

不定数的值组

1
2
3
4
5
namespace std
{
template <typename... Types>
class tuple;
}

Smart Pointer

自c++ 11起,c++标准库提供两大类型的smart pointer

  1. shared_ptr(共享式指针)
    多个smart pointer可以指向相同对象,该对象和其相关资源会在“最后一个reference被销毁”时被释放。
  2. unique_ptr(独占式拥有)
    保证同一时间内只有一个smart pointer可以指向该对象。

数值的极值

数值类型有着与平台相依的极值。
numeric_limits<>
|类型|最小长度|
|–|–|
|char|1 byte|
|short int|2 byte|
|int|2 byte|
|long int|4 byte|
|long long int|8 byte|
|float|4 byte|
|double|8 byte|
|long double|8 byte|

Type Trait和Type Utility

type trait提供一种用来处理type属性的方法。可以用来检查类型的性质,类型的比较。

辅助函数

选择最小值、最大值、交换两值

ratio

编译器分数运算

Clock和Timer

处理日期和时间的程序库。

C++-标准库简介

发表于 2018-11-16 | 更新于 2020-05-17 | 分类于 语言

C++标准的历史

  1. C++98
    于1998年批准,是第一份C++标准规格。官方名称是Information Technology - Programming Languages - C++,文档编号ISO/IEC 14882:1998

  2. C++03
    这是个所谓“技术勘误”(technical corrigendum, TC),内含不甚严重的C++98 bug 修正。文档编号ISO/IEC 14882:2003。

  3. TR1
    内含大幅度的标准库扩充。官方名称是Information Technology - Programming Languages -Technical Report on C++ Library Extensions,文档编号 ISO/IEC TR 19768:2007。它所涵盖的扩充全部包含于namespace std::tr1内。

  4. C++11
    批准于2011年,是第二份C++标准。官方名称Information Technology - Programming Languages -C++,文档编号ISO/IEC 14882:2011。

C++98和C++11的兼容性

C++的设计目标之一是,对C++98保持向后兼容。

  1. C+11

    1
    #define __cplusplus 201103L
  2. c++98和c++03

    1
    #define __cplusplus 199711L

向后兼容仅适用于源码,不保证二进制兼容。所以请以C++11编译器重新编译C++98程序的每一份源码。

汇编语言-基础知识

发表于 2018-11-16 | 更新于 2020-05-17 | 分类于 语言

机器语言是机器指令的集合。电子计算机的机器指令是一列二进制数字,计算机将之转变为一列高低电平,以使计算机的电子器件受到驱动,进行运算。

汇编语言的主体是汇编指令。汇编指令是机器指令便于记忆的书写格式。然后由汇编编译器将其编译为机器码,由计算机最终执行。

例如:
操作:寄存器BX的内容送到AX中
机器指令:1000100111011000
汇编指令:mov ax,bx

汇编语言发展至今,由以下3类指令组成。

  • 汇编指令:机器码的助记符,有对应的机器码。
  • 伪指令:没有对应的机器码,由编译器执行,计算机并不执行。
  • 其他符号:如:+、-、*、/等,由编译器识别,没有对应的机器码。

寄存器

一个典型的CPU由运算器、控制器、寄存器等器件构成,这些器件靠内部总线相连。

对于一个汇编程序员来说,CPU中的主要部件是寄存器。寄存器是CPU中程序员可以用指令读写的部件。通过改变各种寄存器中的内容来实现对CPU的控制。

不同的CPU,寄存器的个数、结构是不相同的。8086CPU有14个寄存器,每个寄存器有一个名称。8086CPU的所有寄存器都是16位的,可以存放两个字节。这些寄存器是:AX,BX,CX,DX,SI,DI,SP,BP,IP,CS,SS,DS,ES,PSW。

通用寄存器

AX,BX,CX,DX四个寄存器通常用来存放一般性的数据,被称为通用寄存器。

1
2
3
mov ax,18
add ax,8
mov ax,bx

段寄存器

8086CPU有4个段寄存器:CS,DS,SS,ES。

8086CPU在访问内存时要由相关部件提供内存单元的段地址和偏移地址,送入地址加法器合成物理地址。

1
2
# jmp 段地址:偏移地址
jmp 2AE3:3

CS和IP

CS和IP指示了CPU当前要读取指令的地址。CS为代码段寄存器,IP为指令指针寄存器。

DS

8086CPU中有一个DS寄存器,通常用来存放要访问数据的段地址。

1
2
3
mov bx,1000H
mov ds,bx
mov al,[0]

[0]中的0表示内存单元的偏移地址。内存单元的段地址自动取DS中的数据为内存单元的段地址。同时,不能直接将数据送入段寄存器,必须通过另外一个寄存器来进行中转,例如这里的bx。

SS和SP

8086CPU中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。

栈

8086CPU提供相关的指令来以栈的方式访问内存空间。8086CPU提供入栈和出栈指令,最基本的两个是PUSH(入栈)和POP(出栈)。
有相应的两个寄存器来存放栈顶的地址,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。

1
2
push 寄存器:将一个寄存器中的数据入栈
pop 寄存器:出栈,用一个寄存器接收出栈的数据

栈顶超界
8086CPU不保证我们对栈的操作不会超界,因此我们在编程的时候要自己操心栈顶超界的问题。实模式下没有任何保护,虚模式下由操作系统进行保护。

实模式:80386处理器被复位或加电的时候以实模式启动,在实模式下,所有的段都是可以读、写和执行的。实模式下处理器没有硬件级的内存保护概念和多道任务的工作模式。
保护模式:又被称作虚拟地址保护模式。保护模式的特性是阻止被其他任务或系统内核破坏已经不健全的程序的运行。
虚模式:虚模式是以任务形式在保护模式上执行的。

中断

任何一个通用的CPU,都具备一种能力,可以在执行完当前正在执行的指令之后,检测到从CPU外部发送过来的或内部产生的一种特殊信息(中断信息),并且可以立即对所接收到的信息进行处理。

内中断

当CPU内部有下面的情况发生的时候,将产生相应的中断信息:

  1. 除法错误
  2. 单步执行
  3. 执行int0指令
  4. 执行int指令

CPU根据中断类型码的数据来标识中断信息的来源。中断类型码为一个字节型数据,可以表示256种中断信息的来源。

中断源 中断类型码
除法错误 0
单步执行 1
执行int0指令 4
执行int指令 指令的格式为int n,指令中的n为字节型数字,是提供给CPU的中断类型码

外中断

当CPU外部有需要处理的事情发生的时候,比如说,外设的输入到达,相关芯片将向CPU发出相应的中断信息。CPU在执行完当前指令后,可以检测到发送过来的中断信息,引发中断过程,处理外设的输入。

###

整理

通过将指令放入CS和IP中,交由CPU执行指令,将数据在AX和BX进行中转,再经DS放回到内存中。

Degbug

Debug是DOS、Windows都提供的实模式程序的调试工具。使用它,可以查看CPU各种寄存器中的内容、内存的情况和在机器码级跟踪程序的运行。

进入Debug

开始>运行>command>debug

Debug常用命令

  • R命令:查看、修改CPU中寄存器的值
  • D命令:查看内存中的内容
  • E命令:改写内存中的内容
  • U命令:查看机器码对应的汇编指令
  • T命令:执行当前指令
  • A命令:以汇编指令的形式在内存中写入机器指令

Java-线程池

发表于 2018-11-16 | 更新于 2020-05-17 | 分类于 Java

1.减少创建线程的次数
2.控制线程池大小,减少并发线程数目

方法 描述
newCachedThreadPool 必要时创建新线程,空闲线程会被保留60秒
newFixedThreadPool 该池包含固定数量的线程,空闲线程会一直被保留
newSingleThreadExecutor 只有一个线程的池,该线程顺序执行每一个提交的任务
newScheduledThreadPool 用于预定执行而构建的固定线程池,替代Timer
newSingleThreadScheduledExecutor 用于预定执行而构建的单线程“池”

requestAnimationFrame

发表于 2018-11-16 | 更新于 2020-05-17 | 分类于 其他

swagger

发表于 2018-11-16 | 更新于 2020-05-17 | 分类于 其他

Java-运行时数据区

发表于 2018-11-16 | 更新于 2020-05-17 | 分类于 Java
  • 程序计数器

每个线程都有独立的程序计数器,用于记录当前线程所执行的字节码的行号指示器。

  • Java虚拟机栈

线程私有。每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,对应一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表存放了编译期可知的各种基本数据类型、对象引用类型和returnAddress类型。
-Xss

  • 本地方法栈

虚拟机使用的Native方法的栈空间。

  • Java堆

所有线程共享的一块内存区域。垃圾收集器管理的主要区域。
相关JVM启动参数:-Xmx, -Xms

  • 方法区

所有线程共享的一块内存区域。存储虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
相关JVM启动参数:

1
2
3
4
5
6
7
8
//(JDK7)方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出
-XX: PermSize=128m -XX:MaxPermSize=512m

//元空间并不在虚拟机中,而是使用本地内存。默认情况下,元空间的大小仅受本地内存限制。
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m

//JIT编译后二进制代码的存放区,满了之后就不再编译,对性能影响很大
-XX:ReservedCodeCacheSize

  • 运行时常量池

方法区的一部分。用于存放编译期生成的各种字面量和符号引用。

  • 直接内存

使用Native函数库直接分配堆外内存,不受Java堆大小的限制。
相关JVM启动参数:-XX:MaxDirectMemorySize

C++-命名规范

发表于 2018-11-16 | 更新于 2020-05-17 | 分类于 语言

格式:作用域部分+类型部分+描述部分

例如:m_nMax,g_nMin

作用域部分

前缀 说明
作用域部分 无 局部变量
作用域部分 m_ 类的成员变量(member)
作用域部分 sm_ 类的静态成员变量(static member)
作用域部分 s_ 静态变量(static)
作用域部分 c_ 常量(const)
作用域部分 g_ 外部全局变量(global)
作用域部分 sg_ 静态全局变量(static global)
作用域部分 gg_ 进程或动态链接库间共享的全局变量(global global)

类型部分

前缀 说明
类型部分 u unsigned
类型部分 by BYTE
类型部分 n 整数和位域变量
类型部分 e 枚举型变量
类型部分 ch char
类型部分 sz char[]
类型部分 l long
类型部分 b 布尔
类型部分 f 浮点
类型部分 p 指针
类型部分 r 引用
类型部分 arr 数组
类型部分 h 句柄

描述部分

前缀 说明
描述部分 Max 最大
描述部分 Min 最小
描述部分 Temp 临时
描述部分 Src 源
描述部分 Dest 目标
1…678…22

Paul Jiang

212 日志
26 分类
26 标签
Links
  • 褚霸
  • 章亦春
  • Martin Fowler
© 2020 Paul Jiang
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Gemini v6.5.0