<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>详解 on 庞玉栋个人博客</title><link>https://pangyd.com/tags/%E8%AF%A6%E8%A7%A3/</link><description>Recent content in 详解 on 庞玉栋个人博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Wed, 11 Dec 2019 10:23:59 +0800</lastBuildDate><atom:link href="https://pangyd.com/tags/%E8%AF%A6%E8%A7%A3/index.xml" rel="self" type="application/rss+xml"/><item><title>Matplotlib 雷达图详解</title><link>https://pangyd.com/post/230-matplotlib/</link><pubDate>Sun, 01 Dec 2019 10:07:16 +0800</pubDate><guid>https://pangyd.com/post/230-matplotlib/</guid><description>&lt;p>创建figure对象&amp;nbsp; 设置画布大小&amp;nbsp; 背景颜色&lt;/p>&lt;p>fig = plt.figure(figsize=(10,8))&lt;/p>&lt;p>创建图形图像&amp;nbsp; 设置以极坐标的方式显示&lt;/p>&lt;p>ax = fig.add_subplot(111,polar=True)&lt;/p>&lt;p>生成角度列表&amp;nbsp;&amp;nbsp;&lt;/p>&lt;p>angle = np.linspace(0,2*np.pi,10，endpoint=False)&lt;/p>&lt;p>首尾相连&amp;nbsp; 形成闭合多边形&lt;/p>&lt;p>&lt;span>theta = np.append(theta, theta[&lt;/span>&lt;span class="hljs-number">0&lt;/span>&lt;span>])&lt;/span>&lt;/p>&lt;p>angle =&amp;nbsp; np.append(angle, angle[&lt;span class="hljs-number">0&lt;/span>])&lt;/p>&lt;p>作图 第一个 角度&amp;nbsp; 第二个 数据&amp;nbsp; 第三个 线条样式&amp;nbsp; 第四个 线段宽度&amp;nbsp; 第五个 标签文本&lt;/p>&lt;p>ax.plot(angle, centers], 'o-', linewidth=2, label=kinds[i])&lt;/p>&lt;p>填充颜色&amp;nbsp;&lt;/p>&lt;p>ax.fill(angle,centers,alpha=0.5)&lt;/p>&lt;p>设置显示标签&amp;nbsp; 设置标签所在位置 透明度&lt;/p>&lt;p>plt.legend(loc='best',bbox_to_anchor=(1.2,0.3,0.,0.8),framealpha=0.1,edgecolor='blue')&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>极坐标柱形图使用bar生成图形&lt;/p>&lt;p>theta = np.linspace(0,2*np.pi,20,endpoint=False)&lt;/p>&lt;p>radii = 10*np.random.rand(20)&lt;/p>&lt;p>width = np.pi/4*np.random.rand(20)&lt;/p>&lt;p>bar = ax.bar(theta,radii,widrth,bottom=0.0)&lt;/p>&lt;p>for a,b in zip(radii,bar):&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp;b.set_facecolor=plt.cm.hot(a/10)&lt;/p>&lt;p>&amp;nbsp; &amp;nbsp;b.set_alpha=0.1&lt;/p></description></item><item><title>flask-sqlalchemy 使用详解</title><link>https://pangyd.com/post/221-flask-sqlalchemy/</link><pubDate>Thu, 03 Oct 2019 19:47:58 +0800</pubDate><guid>https://pangyd.com/post/221-flask-sqlalchemy/</guid><description>&lt;h2 id="一-安装">一. 安装&lt;/h2>&lt;pre class="has" name="code">&lt;code class="hljs sql">$ pip &lt;span class="hljs-keyword">install&lt;/span> flask-sqlalchemy
&lt;/code>&lt;/pre>&lt;h2 id="二-配置">&lt;a name="t1">&lt;/a>二. 配置&lt;/h2>&lt;p>配置选项列表 :&lt;/p>&lt;div class="table-box">&lt;table class="layui-table">&lt;thead>&lt;tr>&lt;th style="text-align: left">选项&lt;/th>&lt;th style="text-align: left">说明&lt;/th>&lt;/tr>&lt;/thead>&lt;tbody>&lt;tr>&lt;td>SQLALCHEMY_DATABASE_URI&lt;/td>&lt;td>用于连接的数据库 URI 。例如:sqlite:////tmp/test.db 或 mysql://username:password@server/db&lt;/td>&lt;/tr>&lt;tr>&lt;td>SQLALCHEMY_BINDS&lt;/td>&lt;td>一个映射 binds 到连接 URI 的字典。更多 binds 的信息见 用 Binds 操作多个数据库 。&lt;/td>&lt;/tr>&lt;tr>&lt;td>SQLALCHEMY_ECHO&lt;/td>&lt;td>如果设置为 Ture ， SQLAlchemy 会记录所有 发给 stderr 的语句，这对调试有用。&lt;/td>&lt;/tr>&lt;tr>&lt;td>SQLALCHEMY_RECORD_QUERIES&lt;/td>&lt;td>可以用于显式地禁用或启用查询记录。查询记录 在调试或测试模式自动启用。更多信息见 get_debug_queries() 。&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>&lt;/div>&lt;p>SQLALCHEMY_NATIVE_UNICODE | 可以用于显式禁用原生 unicode 支持。当使用 不合适的指定无编码的数据库默认值时，这对于 一些数据库适配器是必须的（比如 Ubuntu 上某些版本的 PostgreSQL ）。|&lt;br>| SQLALCHEMY_POOL_SIZE | 数据库连接池的大小。默认是引擎默认值（通常 是 5 ） |&lt;br>| SQLALCHEMY_POOL_TIMEOUT | 设定连接池的连接超时时间。默认是 10 。 |&lt;br>| SQLALCHEMY_POOL_RECYCLE | 多少秒后自动回收连接。这对 MySQL 是必要的， 它默认移除闲置多于 8 小时的连接。注意如果 使用了 MySQL ， Flask-SQLALchemy 自动设定这个值为 2 小时。|&lt;/p></description></item><item><title>Flume配置文件详解</title><link>https://pangyd.com/post/220-flume/</link><pubDate>Wed, 24 Jul 2019 09:26:42 +0800</pubDate><guid>https://pangyd.com/post/220-flume/</guid><description>&lt;p>一、source配置&lt;/p>&lt;p>1、netcat的source：bind指定IP，port指定port&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p># Describe/configure the source&lt;/p>&lt;p>a1.sources.r1.type = netcat&lt;/p>&lt;p>a1.sources.r1.bind = localhost&lt;/p>&lt;p>a1.sources.r1.port = 44444&lt;/p>&lt;p>2、读文件exec：commd中写命令，如果用tail的话记得用大写的F&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p># Describe/configure the source&lt;/p>&lt;p>a1.sources.r1.type = exec&lt;/p>&lt;p>a1.sources.r1.command = tail -F /opt/module/hive/logs/hive.log&lt;/p>&lt;p>a1.sources.r1.shell = /bin/bash -c&lt;/p>&lt;p>3、读取文件夹source：spooldir source ，tmp记得一定要忽略&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p># Describe/configure the source&lt;/p>&lt;p>a1.sources.r1.type = spooldir&lt;/p>&lt;p># 指定文件夹&lt;/p>&lt;p>a1.sources.r1.spoolDir = /opt/module/flume/upload&lt;/p>&lt;p>#指定文件上传后的后缀&lt;/p>&lt;p>a1.sources.r1.fileSuffix = .COMPLETED&lt;/p>&lt;p>a1.sources.r1.fileHeader = true&lt;/p>&lt;p>#忽略所有以.tmp结尾的文件，不上传&lt;/p>&lt;p>a1.sources.r1.ignorePattern = ([^ ]*\.tmp)&lt;/p>&lt;p>4、最常用的source: arvo模式，bind指的是接收的主机，port不是随意的，是看sink给的端口&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p># Describe/configure the source&lt;/p>&lt;p>a1.sources.r1.type = avro&lt;/p></description></item><item><title>re正则模块详解</title><link>https://pangyd.com/post/206-re/</link><pubDate>Wed, 07 Nov 2018 08:10:45 +0800</pubDate><guid>https://pangyd.com/post/206-re/</guid><description>&lt;p>re正则表达式是一种工具，和其他工具一样，它是人们为了解决某一类专门的问题而发明的。想要理解正则表达式及其功用。最好的办法是了解他们可以解决什么样的问题&lt;/p>&lt;p>正则表达式的主要用途之一是搜索变化多端的文本，比如，搜索以http开头的 以句号等空白字结尾的字符串&amp;nbsp;&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>&lt;/p>&lt;pre lay-lang="Python" class="layui-code" skin="notepad">import re
&lt;p>text = &amp;ldquo;The Attila the Hun Show&amp;rdquo;&lt;/p>
&lt;h1 id="a-single-character-单个字符">a single character 单个字符&lt;/h1>
&lt;p>m = re.match(&amp;quot;.&amp;quot;, text)
if m: print repr(&amp;quot;.&amp;quot;), &amp;ldquo;=&amp;gt;&amp;rdquo;, repr(m.group(0))&lt;/p>
&lt;h1 id="any-string-of-characters-任何字符串">any string of characters 任何字符串&lt;/h1>
&lt;p>m = re.match(&amp;quot;.&lt;em>&amp;quot;, text)
if m: print repr(&amp;quot;.&lt;/em>&amp;quot;), &amp;ldquo;=&amp;gt;&amp;rdquo;, repr(m.group(0))&lt;/p>
&lt;h1 id="a-string-of-letters-at-least-one-只包含字母的字符串至少一个">a string of letters (at least one) 只包含字母的字符串(至少一个)&lt;/h1>
&lt;p>m = re.match(&amp;quot;\w+&amp;quot;, text)
if m: print repr(&amp;quot;\w+&amp;quot;), &amp;ldquo;=&amp;gt;&amp;rdquo;, repr(m.group(0))&lt;/p>
&lt;h1 id="a-string-of-digits-只包含数字的字符串">a string of digits 只包含数字的字符串&lt;/h1>
&lt;p>m = re.match(&amp;quot;\d+&amp;quot;, text)
if m: print repr(&amp;quot;\d+&amp;quot;), &amp;ldquo;=&amp;gt;&amp;rdquo;, repr(m.group(0))&lt;/p></description></item><item><title>Python中操作mysql的pymysql模块详解</title><link>https://pangyd.com/post/197-pythonmysqlpymysql/</link><pubDate>Mon, 06 Aug 2018 18:06:31 +0800</pubDate><guid>https://pangyd.com/post/197-pythonmysqlpymysql/</guid><description>&lt;div>&lt;div>&lt;div class="article">&lt;div data-note-content="" class="show-content">&lt;div class="show-content-free">&lt;p>&lt;a href="https://link.jianshu.com?t=https://github.com/PyMySQL/PyMySQL" target="_blank" rel="nofollow">PyMySQL&lt;/a>是一个Python编写的MySQL驱动程序，让我们可以用Python语言操作MySQL数据库。&lt;/p>
&lt;p>首先，使用pip安装PyMySQL。&lt;/p>
&lt;pre class="hljs undefined">&lt;code>pip install PyMySQL
&lt;/code>&lt;/pre>
&lt;h2>使用PyMySQL&lt;/h2>
&lt;h3>简单使用&lt;/h3>
&lt;p>如果有JDBC等其他语言的数据库学习经验的话，使用PyMySQL非常简单。下面是一个完整的MySQL增删查（没有改）的例子。&lt;/p>
&lt;pre class="hljs python">&lt;code class="python">&lt;span class="hljs-keyword">import&lt;/span> pymysql
&lt;span class="hljs-keyword">import&lt;/span> datetime
&lt;p>host = &lt;span class="hljs-string">&amp;lsquo;localhost&amp;rsquo;&lt;/span>
username = &lt;span class="hljs-string">&amp;lsquo;root&amp;rsquo;&lt;/span>
password = &lt;span class="hljs-string">&amp;lsquo;12345678&amp;rsquo;&lt;/span>
db_name = &lt;span class="hljs-string">&amp;lsquo;test&amp;rsquo;&lt;/span>&lt;/p>
&lt;p>create_table_sql = &lt;span class="hljs-string">&amp;quot;&amp;quot;&amp;quot;&lt;br>
CREATE TABLE fuck(
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) UNIQUE ,
nickname VARCHAR(255) NOT NULL ,
birthday DATE
)
&amp;ldquo;&amp;rdquo;&amp;quot;&lt;/span>&lt;/p>
&lt;p>insert_table_sql = &lt;span class="hljs-string">&amp;quot;&amp;quot;&amp;quot;&lt;br>
INSERT INTO fuck(username,nickname,birthday)
VALUES(&amp;rsquo;{username}&amp;rsquo;,&amp;rsquo;{nickname}&amp;rsquo;,&amp;rsquo;{birthday}&amp;rsquo;)
&amp;ldquo;&amp;rdquo;&amp;quot;&lt;/span>&lt;/p>
&lt;p>query_table_sql = &lt;span class="hljs-string">&amp;quot;&amp;quot;&amp;quot;&lt;br>
SELECT id,username,nickname,birthday
FROM fuck
&amp;ldquo;&amp;rdquo;&amp;quot;&lt;/span>&lt;/p>
&lt;p>delete_table_sql = &lt;span class="hljs-string">&amp;quot;&amp;quot;&amp;quot;&lt;br>
DELETE FROM fuck
&amp;ldquo;&amp;rdquo;&amp;quot;&lt;/span>&lt;/p>
&lt;p>drop_table_sql = &lt;span class="hljs-string">&amp;quot;&amp;quot;&amp;quot;&lt;br>
DROP TABLE fuck
&amp;ldquo;&amp;rdquo;&amp;quot;&lt;/span>&lt;/p></description></item><item><title>Java 中的异常和处理详解</title><link>https://pangyd.com/post/122-java/</link><pubDate>Tue, 03 Oct 2017 19:16:17 +0800</pubDate><guid>https://pangyd.com/post/122-java/</guid><description>&lt;p>&lt;br>&lt;/p>&lt;p>&lt;strong>&lt;span>简介&lt;/span>&lt;/strong>&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>程序运行时，发生的不被期望的事件，它阻止了程序按照程序员的预期正常执行，这就是异常。异常发生时，是任程序自生自灭，立刻退出终止，还是输出错误给用户？或者用C语言风格：用函数返回值作为执行状态？。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>Java提供了更加优秀的解决办法：异常处理机制。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>异常处理机制能让程序在异常发生时，按照代码的预先设定的异常处理逻辑，针对性地处理异常，让程序尽最大可能恢复正常并继续执行，且保持代码的清晰。&lt;/p>&lt;p>Java中的异常可以是函数中的语句执行时引发的，也可以是程序员通过throw 语句手动抛出的，只要在Java程序中产生了异常，就会用一个对应类型的异常对象来封装异常，JRE就会试图寻找异常处理程序来处理异常。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>Throwable类是Java异常类型的顶层父类，一个对象只有是 Throwable 类的（直接或者间接）实例，他才是一个异常对象，才能被异常处理机制识别。JDK中内建了一些常用的异常类，我们也可以自定义异常。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>&lt;strong>&lt;span>Java异常的分类和类结构图&lt;/span>&lt;/strong>&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>Java标准裤内建了一些通用的异常，这些类以Throwable为顶层父类。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>Throwable又派生出Error类和Exception类。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>错误：Error类以及他的子类的实例，代表了JVM本身的错误。错误不能被程序员通过代码处理，Error很少出现。因此，程序员应该关注Exception为父类的分支下的各种异常类。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>异常：Exception以及他的子类，代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用，是异常处理的核心。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p style="text-align: center">&lt;img class="" title="858860-20170911125844719-1230755033" data-src="https://pangyd.com/uploads/2017/10/74c10f869f038762.png" data-ratio="0.637883008356546" data-w="718" data-type="png" src="https://pangyd.com/uploads/2017/10/74c10f869f038762.png" data-fail="0">&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>总体上我们根据Javac对异常的处理要求，将异常类分为2类。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>非检查异常（unckecked exception）：Error 和 RuntimeException 以及他们的子类。javac在编译时，不会提示和发现这样的异常，不要求在程序处理这些异常。所以如果愿意，我们可以编写代码处理（使用try…catch…finally）这样的异常，也可以不处理。对于这些异常，我们应该修正代码，而不是去通过异常处理器处理 。这样的异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException，错误的强制类型转换错误ClassCastException，数组索引越界ArrayIndexOutOfBoundsException，使用了空对象NullPointerException等等。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>检查异常（checked exception）：除了Error 和 RuntimeException的其它异常。javac强制要求程序员为这样的异常做预备处理工作（使用try…catch…finally或者throws）。在方法中要么用try-catch语句捕获它并处理，要么用throws子句声明抛出它，否则编译不会通过。这样的异常一般是由程序的运行环境导致的。因为程序可能被运行在各种未知的环境下，而程序员无法干预用户如何使用他编写的程序，于是程序员就应该为这样的异常时刻准备着。如SQLException , IOException,ClassNotFoundException 等。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>需要明确的是：检查和非检查是对于javac来说的，这样就很好理解和区分了。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>&lt;strong>&lt;span>初识异常&lt;/span>&lt;/strong>&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>下面的代码会演示2个异常类型：ArithmeticException 和 InputMismatchException。前者由于整数除0引发，后者是输入的数据不能被转换为int类型引发。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;blockquote>&lt;p>&lt;span>package com.example;&lt;/span>&lt;/p>&lt;p>&lt;span>import java. util .Scanner ;&lt;/span>&lt;/p>&lt;p>&lt;span>public class AllDemo&lt;/span>&lt;/p>&lt;p>&lt;span>{&lt;/span>&lt;/p>&lt;p>&lt;span>&amp;nbsp; &amp;nbsp; &amp;nbsp; public static void main (String [] args )&lt;/span>&lt;/p></description></item><item><title>Java中堆内存和栈内存详解</title><link>https://pangyd.com/post/80-java/</link><pubDate>Sun, 27 Aug 2017 19:13:26 +0800</pubDate><guid>https://pangyd.com/post/80-java/</guid><description>&lt;p>Java把内存分成两种，一种叫做栈内存，一种叫做堆内存.&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时，java就在栈中为这个变量分配内存空间，当超过变量的作用域后，java会自动释放掉为该变量分配的内存空间，该内存空间可以立刻被另作他用。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>堆内存用于存放由new创建的对象和数组。在堆中分配的内存，由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后，还可以在栈中定义一个特殊的变量，这个变量的取值等于数组或者对象在堆内存中的首地址，在栈中的这个特殊的变量就变成了数组或者对象的引用变量，以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象，引用变量相当于为数组或者对象起的一个别名，或者代号。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>引用变量是普通变量，定义时在栈中分配内存，引用变量在程序运行到作用域外释放。而数组＆对象本身在堆中分配，即使程序运行到使用new产生数组和对象的语句所在地代码块之外，数组和对象本身占用的堆内存也不会被释放，数组和对象在没有引用变量指向它的时候，才变成垃圾，不能再被使用，但是仍然占着内存，在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因，实际上，栈中的变量指向堆内存中的变量，这就是 Java 中的指针!&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>java中内存分配策略及堆和栈的比较&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>1 内存分配策略&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的.&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求.&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存.和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放.&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>2 堆和栈的比较&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>上面的定义从编译原理的教材中总结而来,除静态存储分配之外,都显得很呆板和难以理解,下面撇开静态存储分配,集中比较堆和栈:&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的，栈主要是用来执行程序的.而这种不同又主要是由于堆和栈的特点决定的:&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>在编程中，例如C/C++中，所有的方法调用都是通过栈来进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。实际上也不是什么分配,只是从栈顶向上用就行,就好像工厂中的传送带(conveyor belt)一样,Stack Pointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候，修改栈指针就可以把栈中的内容销毁.这样的模式速度最快, 当然要用来运行程序了.需要注意的是,在分配的时候,比如为一个即将要调用的程序模块分配数据区时,应事先知道这个数据区的大小,也就说是虽然分配是在程序运行时进行的,但是分配的大小多少是确定的,不变的,而这个”大小多少”是在编译时确定的,不是在运行时.&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>堆是应用程序在运行的时候请求操作系统分配给自己内存，由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间，因此用堆的效率非常低.但是堆的优点在于,编译器不必知道要从堆里分配多少存储空间，也不必知道存储的数据要在堆里停留多长的时间,因此,用堆保存数据时会得到更大的灵活性。事实上,面向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定.在C++中，要求创建一个对象时，只需用 new命令编制相关的代码即可。执行这些代码时，会在堆里自动进行数据的保存.当然，为达到这种灵活性，必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!这也正是导致我们刚才所说的效率低的原因,看来列宁同志说的好,人的优点往往也是人的缺点,人的缺点往往也是人的优点(晕~).&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>3 JVM中的堆和栈&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说，它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的 Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译原理中的活动纪录的概念是差不多的.&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>从Java的这种分配机制来看,堆栈又可以这样理解:堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域，该区域具有先进后出的特性。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>每一个Java应用都唯一对应一个JVM实例，每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程共享.跟C/C++不同，Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的，但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存，在堆中分配的内存实际建立这个对象，而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>Java 中的堆和栈&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>Java把内存划分成两种：一种是栈内存，一种是堆内存。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>当在一段代码块定义一个变量时，Java就在栈中为这个变量分配内存空间，当超过变量的作用域后，Java会自动释放掉为该变量所分配的内存空间，该内存空间可以立即被另作他用。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>堆内存用来存放由new创建的对象和数组。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>在堆中分配的内存，由Java虚拟机的自动垃圾回收器来管理。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>在堆中产生了一个数组或对象后，还可以在栈中定义一个特殊的变量，让栈中这个变量的取值等于数组或对象在堆内存中的首地址，栈中的这个变量就成了数组或对象的引用变量。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>引用变量就相当于是为数组或对象起的一个名称，以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>具体的说：&lt;/p>&lt;p>&lt;br>&lt;/p>&lt;p>栈与堆都是Java用来在Ram中存放数据的地方。与C++不同，Java自动管理栈和堆，程序员不能直接地设置栈或堆。&lt;/p></description></item></channel></rss>