比特如何存储在内存中? (在块中?可以存储多个大小的位吗?)

问题描述 投票:6回答:8

我曾经认为每个内存位置包含8位,16位,32位或64位。因此0101将作为00000101存储在8位机器中(如果是负数则符号扩展)。这是好的和花花公子,直到我出于好奇心在java中编写一个程序,以找出这个系统的更多内部工作。

有问题的方法如下:

public void printBinaryRep(File f){
        try{
            FileInputStream inputStream = new FileInputStream(f);
            int next = 0;
            byte b = 0;
            while((next = inputStream.read()) != -1){
                b = (byte)next;
                System.out.println((char)next + " : "+Integer.toBinaryString(next));
            }
            inputStream.close();
        }
        catch(Exception e){System.out.println(e);}
 }

我从一个写着Hello World的文件中得到了这个输出

H : 1001000
e : 1100101
l : 1101100
l : 1101100
o : 1101111
  : 100000
W : 1010111
o : 1101111
r : 1110010
l : 1101100
d : 1100100

除了空间外,所有这些都很好看。它有6位而不是8位。我现在想知道所有这些信息是如何存储在内存中的。如果所有这些都存储在8位块中,比如

您好:10010001100101110110011011001101111

然后你可以简单地查看每个8位块并找出它所代表的数字(然后是它所指的ASCII码)。当一个不同大小的字符(如6位空格和4位/ n)与它们一起存储时,它是如何工作的?那么不会在大的位空间中存储少量的数据会浪费很多比特吗?

我认为我有一些基本的理解错误(或者某个地方的程序错了......)。对不起,如果这个问题听起来很奇怪或太不必要。我只是想知道。我做了一些谷歌搜索,但它没有提出任何相关的东西。如果你能让我知道我哪里出错了或者指出了我正确的方向,我会非常感激。谢谢!

java memory binary bit computer-architecture
8个回答
9
投票

你最好在C和/或汇编中进行实验,而不是Java。这些语言是较低级别的,并直接暴露地址空间。

我曾经认为每个内存位置包含8位,16位,32位或64位。因此0101将作为00000101存储在8位机器中(如果是负数则符号扩展)。这是好的和花花公子,直到我出于好奇心在java中编写一个程序,以找出这个系统的更多内部工作。

x86系统中的所有内存位置都包含8位(1个字节)。如果某个值包含的数据超过单个字节的数据,则使用多个字节进行存储。例如,在C中,“float”类型使用4个字节(32位)存储。

除了空间外,所有这些都很好看。它有6位而不是8位。我现在想知道所有这些信息是如何存储在内存中的。如果所有这些都存储在8位块中,比如

该空间也存储在一个字节中。您的打印代码忘记填充8个空格。 100000 == 00100000 == 0x20。


7
投票

空间也有8位。只是Integer.toBinaryString不会像你使用它那样打印领先的0位。

使用所有领先的0位,它实际上在内存中看起来像这样:

H : 01001000
e : 01100101
l : 01101100
l : 01101100
o : 01101111
  : 00100000
W : 01010111
o : 01101111
r : 01110010
l : 01101100
d : 01100100

4
投票

您的原始直觉(大多数)是正确的:所有内存位置都包含相同的位数。在所有现代机器上,“byte”中有8位,其中一个字节是机器可以单独访问的最小内存块。

仔细查看您的输出。除空格外,所有这些数字都有七位数。空间恰好以二进制表示中的两个零开头,而其他字母以一个开头。


3
投票

实际上你的做法是错误的。编码在这里非常重要。

如果你使用ASCII,那么你很容易说每个字符都存储在一个字节(8位)中,但是当编码改变时你不能这么说。

例如:UTF-8对字符串上的每个字符使用一到三个字节(8到24位)。这就是为什么你会看到一个重载,你可以在其中指定inputstream对象的编码。

选择错误的输入流绝对会导致错误的字符串输出。因此,您必须知道文件的编码,以了解哪个位意味着什么。实际上fileinputstream会为你做这件事。

如果将数字存储为字符串,则在硬盘驱动器中将占用字符长度。就像另一个角色一样。

但是,如果将123456789存储为ASCII编码的字符串,则需要9 * 8位= 72位。

如果将其存储为整数(注意整数的数据宽度在不同的环境中不同),它只需要16位。

你也不能确定

H : 01001000
e : 01100101
l : 01101100
l : 01101100
o : 01101111
  : 00100000
W : 01010111
o : 01101111
r : 01110010
l : 01101100
d : 01100100
\n: 00001010

存储在硬盘驱动器中为H:01001000 e:01100101 l:01101100 l:01101100 o:01101111:00100000 W:01010111 o:01101111 r:01110010 l:01101100 d:01100100 \ n:00001010

你无法确定这一点。文件系统并不那么简单。也许Hello是连续的,但是World string是在驱动器的末尾。这就是为什么有碎片整理命令。

但是如果我们在定义字符串时谈论主存储器(RAM),我希望位是连续的。至少在C中它是。你定义一个这样的字符串。

char[100] value; // c is a char array. (there is no string type in c)

这里value [0]是我们字符串的第一个字符。并且value仅对内存中的char数组位置进行寻址。

如果value [0]的地址是10,则值[1]的地址是10 + 8 = 18。


3
投票

计算机存储数字的方式可以与汽车里程表进行比较。如果里程表有4位数,它将数字33存储为“0033”。

如果有人问你的里程数是多少,你就不会说“零零零三十三”。默认情况下,Java也没有。 (虽然你可以告诉它。)

那么不会在大的位空间中存储少量的数据会浪费很多比特吗?

好吧,不是真的。假设你的内存中有11000100。计算机应该如何知道这意味着11000100,或11000后跟100,还是1后跟1000后跟100,依此类推?

好吧,实际上计算机只是遵循它给出的程序(请记住,Java程序部分是由您创建的,部分是由设计Java的人创建的)。如果您可以创建一个可行的系统来保存位,您可以让计算机执行此操作。

但是,请记住,在处理器使用和编程难度方面存在折衷。由于典型的计算机可以比使用7位或可变位数更快地处理字节,因此以字节存储ASCII代码是存储文本的一种非常常见的选择。

但让我回到你的问题。

那么不会在大的位空间中存储少量的数据会浪费很多比特吗?

从数学角度讲,没有。一个名为Information Theory的数学分支告诉我们,绝对必要的位数取决于你想要编码的可能性以及它们各自的可能性。

假设您只有四个字母的字母(A,B,C,D),并使用两位数字(分别为00,01,10,11)来表示它。如果这些字母中的每一个都具有相同的可能性,则每个字母所需的最小位数(平均)为2.换句话说,即使A为00且B为01,也没有浪费的位。

另一方面,如果您使用ASCII并将A,B,C,D编码为以下7位数字:

A: 1000001
B: 1000010
C: 1000011
D: 1000100

那么你每个字母“浪费”5位(即使你不是“在一个大的位空间中存储小数字”)。

在设计压缩算法时,这些考虑因素很重要,对于日常应用程序而言并不那么重要。如果你想学习C,理解位和字节当然很重要。


2
投票

根据Java 4 API

如果参数为负,则无符号整数值为参数加232;否则它等于参数。该值转换为二进制(基数2)中的ASCII数字字符串,没有额外的前导0。

实际上,数据存储实际上要复杂得多。为了提高处理效率,大多数数据类型都存储在字边界,这意味着32位机器上的4个字节,或64位机器上的8个字节。阵列可以更紧密地包装,因此char [4]可能最终使用与char相同数量的“实际空间”。

Java是一个虚拟机,我不确定它使用的内存架构(如果有的话)。


1
投票

这清除了它。我的主要问题是我在开始时忽略了零。我正在尝试这个,因为我正在阅读更多有关压缩算法的信息(即gzip)我假设所有这些都是ASCII。看到表示不是程序的目标,但是每个单词的不同位数使我偏离了为我正在处理的文件类型实现基本的,基于索引的压缩的最初目标。一旦我在Java中有一个概念证明,我会尝试在C中重写它。

谢谢!


0
投票

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Integer.html#toBinaryString%28int%29 Integer.ToBinarys的规范如下:

“此值转换为二进制(基数2)中的ASCII数字字符串,没有额外的前导0”

你忽略了这个事实是导致你困惑的原因。

© www.soinside.com 2019 - 2024. All rights reserved.