当前位置:网站首页>ByteDance Interviewer: how to calculate the memory size occupied by a picture

ByteDance Interviewer: how to calculate the memory size occupied by a picture

2022-07-05 10:12:00 A bird carved in the desert

stay Android in , How to calculate the size of a picture in memory , If you want to optimize , Where can we start .

put questions to
Before reading this article , Let's think about some questions first :

Q1: a sheet png Format picture , Picture file size is 55.8KB, So what is the size when it is loaded into memory ?

Q2: Why sometimes , The same app,app The same interface in , The same picture on the interface , But the memory consumption is different on different devices ?

Q3: The same picture , The size of the controls displayed on the interface is different , Will its memory size change with it ?

Q4: The memory size formula used by pictures : Image resolution * The size of each pixel , Is that right , Or rigorous ?

Q5: How to optimize the memory size of pictures ?

Text

stay Android In development , Images often need to be optimized , Because pictures can easily run out of memory . that , We need to know , How to calculate the size of a picture , When loaded into memory , How much space does it take ?

Let's look at a picture first :

This is an ordinary png picture , Take a look at its specific information :

The resolution of the picture is 1080*452, And this one we saw on the computer png The picture size is only 55.8KB, So here comes the question :

The size of the one we see is 55.8KB Of png picture , The size it occupies in memory is also 55.8KB Do you ?

It's important to sort this out , Because I met someone who said , I only need a few pictures KB, Although hundreds of pages are displayed on the interface , But why is the memory footprint so high ?

therefore , We need to figure out a concept : What we see on the computer png Format or jpg Format picture ,png(jpg) Just the container of this picture , They convert the information of each pixel of the original image into another data format through the corresponding compression algorithm , So as to achieve the purpose of compression , Reduce picture file size .

And when we pass the code , When loading this picture into memory , Will first parse the data format of the image file itself , Then restore to bitmap , That is to say Bitmap object ,Bitmap The size of depends on both the data format of the pixel and the resolution .

therefore ,** a sheet png perhaps jpg Format picture size , It's completely different from the size of the image loaded into memory .** You can't say , I jpg The picture is 10KB, Then it only occupies 10KB Of memory space , It's not right .

that , How to calculate the memory space occupied by a picture ?

A great God's article attached at the end is particularly detailed , If you are interested, you can have a look at . I'm not going to talk so professionally here , Let's talk to you according to my rough understanding .

Picture memory size

Many articles on the Internet will introduce , The formula for calculating the memory size occupied by a picture : The resolution of the * The size of each pixel .

this sentence , Yes, yes , It's not right to say that , I just think , If not combined with the scene , It's a little lax to express it directly .

stay Android Native Bitmap In operation , In some cases , When the picture is loaded into memory, the resolution will go through a layer of conversion , therefore , Although the final image size is still calculated by the resolution * Pixel size , But the resolution at this time is not the resolution of the picture itself .

Let's do an experiment , From the following scenarios where several consideration points are combined with each other , Load the same picture , Take a look at the size of the occupied memory space :

  • Different sources of pictures : disk 、res Resource file
  • Different formats of picture files :png、jpg
  • Pictures show controls of different sizes
  • Different Android System equipment

The test code template is as follows :

private void loadResImage(ImageView imageView) {    BitmapFactory.Options options = new BitmapFactory.Options();    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.weixin, options);    //Bitmap bitmap = BitmapFactory.decodeFile("mnt/sdcard/weixin.png", options);    imageView.setImageBitmap(bitmap);    Log.i("!!!!!!", "bitmap:ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount());    Log.i("!!!!!!", "width:" + bitmap.getWidth() + ":::height:" + bitmap.getHeight());    Log.i("!!!!!!", "inDensity:" + options.inDensity + ":::inTargetDensity:" + options.inTargetDensity);    Log.i("!!!!!!", "imageview.width:" + imageView.getWidth() + ":::imageview.height:" +     imageView.getHeight());}

ps: Just to mention here , Use Bitmap Of getByteCount() Method to get the memory size occupied by the current picture , Of course. api 19 Then there's another way , And when bitmap The meaning of the size obtained during reuse also changes , These special scenes will not be discussed in detail , If you are interested, please refer to . Anyway, I know here , Most scenes can be through getByteCount() The memory size occupied by printing pictures can be used to verify our experiment .

The picture is the one above : A resolution of 1080*452 Of png Format picture , The size of the picture file itself 56KB

  See , It's the same picture , But in different scenarios , The amount of memory used may be different , The details will be analyzed later . The different sources of pictures are listed in the above scene , Different Android equipment , Show the different sizes of the controls. These are the scenarios under consideration . Let's continue to look at a scenario : The same picture , Save in different formats ( It's not a rename , With the help of ps);

picture : The resolution of the 1080*452 Of jpg Format picture , The size of the picture file itself 85.2KB

ps: The same picture above , Only by PhotoShop Stored as jpg Format


Several scenarios listed here , The serial number of the experimental subjects compared in each scene is also written at the end of each line , We can compare and confirm by ourselves , Did you find out , The data are the same , So here's a conclusion :

Different formats of pictures :png perhaps jpg It has no effect on the memory size occupied by the picture

Okay , Let's start by analyzing these experimental data :

First , If according to the calculation formula of picture size : The resolution of the * Pixel size

that , According to this formula, the size of this picture should be :1080 * 452 * 4B = 1952640B ≈ 1.86MB

ps: Here, the pixel size is expressed in 4B To calculate because , When not specified , The system defaults to ARGB_8888 Data format as pixels , Other formats are as follows :

  • ALPHA_8 – (1B)
  • RGB_565 – (2B)
  • ARGB_4444 – (2B)
  • ARGB_8888 – (4B)
  • RGBA_F16 – (8B)

In the above experiments , It should be this size , that , Why are there other sizes of data ? therefore , Let's analyze it one by one :

Analysis point 1

Look at the serial number first 1,2 The experiment of , The only difference between the two is the size of the space shown in the picture . This test is done because , Some people will think , The size of the memory space occupied by the picture is related to the size of the picture displayed on the interface , The larger the display control, the more memory it takes . obviously , This understanding is wrong .

Think , The picture must be loaded into memory first , To draw on the control , So when the picture wants to apply for memory space , It doesn't know the size of the control to display at this time , How can the size of the control affect the memory space occupied by the picture , Unless informed in advance , Manually participate in the picture loading process .

Analysis point 2

Let's look at the serial number 2,3,4 The experiment of , The difference between the three , It's just that the picture is res In different resource directories within . When the picture is placed on res When in different directories within , Why is the size of the final picture loaded into memory different ?

If you go and see Bitmap.decodeResource() Source code , You will find , The system is loading res Resource pictures in the directory , It will make a resolution conversion according to the different directories where the pictures are stored , The rule of transformation is :

The height of the new map = Original height * ( The equipment dpi / The directory corresponds to dpi )

The width of the new graph = The width of the original * ( The equipment dpi / The directory corresponds to dpi )

Directory name and dpi The corresponding relationship is as follows ,drawable No suffix corresponds to 160 dpi:

therefore , Let's look at the serial number 2 The experiment of , According to the above theory , Let's calculate the memory size of this picture :

Converted resolution :1080 * (240/160) * 452 * (240/160) = 1620 * 678

obviously , The resolution at this time is not the resolution of the original image , After a layer of conversion , Finally, calculate the picture size :

1620 * 678 * 4B = 4393440B ≈ 4.19MB

Now I know the serial number 2 How did you get the results of your experiment , Same thing , Serial number 3 The purpose of the resource is hdpi The corresponding is 240, And equipment dpi It happens to be 240, So the resolution after conversion is still the original image itself , The result will be 1.86MB.

To sum up :

be located res Pictures in different resource directories in , When loaded into memory , It will go through a resolution conversion first , Then calculate the size , The influencing factor of conversion is the equipment dpi And different resource directories .

Analysis point 3

Based on analysis points 2 The theory of , Look at the serial number 5,6,7 The experiment of , These three experiments are actually used to follow the serial number 2,3,4 The experiments are compared , That's it 6 The conclusion we can draw from an experiment is :

  • Same picture , In the same device , If the picture is placed in res Under different resource directories in , Then the memory space occupied by the picture will be different
  • Same picture , Put it in res In the same resource directory , But in different ways dpi Of the devices , The memory space occupied by pictures will also be different

therefore , This is likely to happen , The same app, But running in a different dpi On the device , The same interface , But the memory consumed may be different .

Why is it said here that it may be different ? According to the above theory , Same picture , Same as catalog , But it's different dpi equipment , Obviously, the resolution conversion is different , The memory consumption should be different , Why use the saying that it is possible ?

emmm, Continue to look at the following analysis points .

Analysis point 4

Serial number 8,9 The experiment of , In fact, I want to verify whether it is only when the source of the image is res There will be resolution conversion in , The results do prove , When the picture is on disk ,SD Card or ,assert The catalogue is also good , The Internet is good ( In fact, the pictures on the network are finally downloaded to disk ), As long as it's not res In the table of contents , Then the calculation formula of the memory occupied by the picture , That is, according to the resolution of the original picture * Pixel size .

Actually , Go and have a look when you're free BitmapFactory Source code , Indeed, only decodeResource() The method will be internally based on dpi Perform resolution conversion , other decodeXXX() There is no the .

that , Why in the last section , In particular , Even if the same app, But running in a different dpi On the device , The same interface , But the memory consumed may be different . Why use the word "possible" here ?

Is that so? , Let's think about it . According to our sorted theory , The calculation formula of the memory size of the picture is : The resolution of the * Pixel size , Then if the source of the picture is res Words , We need to pay attention to , Which resource directory is the picture placed in , And the equipment itself dpi value , Because the system takes res The resource images in the will be converted once according to these two points , In this case , The memory size of the picture is certainly different ?

emmm, It depends on your own factors , If you develop app, The relevant operations of the picture are through BitmapFactory To operate , Then the above question can be replaced by a positive expression . But now , No one else writes their own ,Github There are so many powerful open source image libraries on the Internet , And different image open source libraries , Internal image loading processing , Cache policy , Reuse strategies are different .

therefore , If you use an open source image library , So how much space does it take to load a picture into memory , You need to go deep into the image open source library to analyze its processing .

Because basically all the open source image libraries , Will optimize the image operation , So let's continue to talk about the optimization of pictures .

Picture optimization

With the above theoretical basis , Now think again if the picture takes up too much memory space , To optimize , Some directions you can start , It's also more attractive .

The formula for the size of memory occupied by pictures is : The resolution of the * Pixel size , It's just that in some situations , For example, the source of the picture is res Words , Maybe the resolution of the final image is not the resolution of the original image , But at the end of the day , For computers , It's really calculated according to this formula .

therefore , If we only consider the optimization from the picture itself , There are only two directions :

  • Reduce resolution
  • Reduce the size of each pixel

In addition to considering the picture itself , Other aspects can be like memory alert , Manual cleaning , Pictures, weak references, etc .

Reduce pixel size

The second direction is easy to operate , After all, the system defaults to ARGB_8888 Format for processing , Then each pixel will occupy 4B Size , Changing this format will naturally reduce the size of memory occupied by pictures .

Common is , take ARGB_8888 Switch to RGB_565 Format , But the latter does not support transparency , So this scheme is not universal , It's up to you app Transparency requirements of pictures in , Of course, you can also cache ARGB_4444, But it will reduce the quality .

Because it basically uses the image open source library , Here are some ways to deal with the image open source library :

//fresco, By default ARGB_8888Fresco.initialize(context, ImagePipelineConfig.newBuilder(context).setBitmapsConfig(Bitmap.Config.RGB_565).build()); //Glide, Different versions , The pixel format is different public class GlideConfiguration implements GlideModule {         @Override      public void applyOptions(Context context, GlideBuilder builder) {          builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);      }         @Override      public void registerComponents(Context context, Glide glide) {      }  }  // stay AndroidManifest.xml Lieutenant general GlideModule Defined as meta-data<meta-data android:name="com.inthecheesefactory.lab.glidepicasso.GlideConfiguration" android:value="GlideModule"/>   //Picasso, Default  ARGB_8888Picasso.with(imageView.getContext()).load(url).config(Bitmap.Config.RGB_565).into(imageView);

The above code is extracted from the network , Correctness should be credible , It hasn't been verified , Interested to go to the relevant source code to confirm .

Reduce resolution

If you can make the system load pictures , The resolution of the original image shall not prevail , But reduce a certain proportion , that , Naturally, the effect of reducing picture memory can be achieved .

alike , The system provides relevant information API:

BitmapFactory.Options.inSampleSize

Set up inSampleSize after ,Bitmap The width of 、 The height will shrink inSampleSize times . for example : The width and height of one sheet is 2048x1536 Pictures of the , Set up inSampleSize by 4 after , The width and height of the picture actually loaded into memory is 512x384. The memory occupied is 0.75M instead of 12M, It saves 15 times

The above paragraph is excerpted from the article with the link given at the end , There are also many articles on how to operate on the Internet , I won't go into details here . I haven't seen the internal processing of those open source image libraries yet , But I guess , They optimize the processing of pictures , It should also be through this API To operate .

Actually , No matter which image open source library , When loading pictures , There must be an internal optimization of the picture , Even if we didn't manually specify the image compression processing . This is what I said above , Why when you use the open source image library , You can no longer calculate the reason why pictures occupy memory size according to the theory described in the picture memory size section .

We can do an experiment , Let's take a look at fresco The experiment of :


If you use fresco, So no matter where the picture comes from , The resolution is calculated based on the resolution of the original image , The data obtained from the can also confirm ,fresco For the size of pixels, the default is ARGB_8888 Format processing .

I guess ,fresco Internal for loading res The picture of , You should first get the picture file object in its own way , Finally, it may be through BitmapFactory Of decodeFile() perhaps decodeByteArray() And so on , Anyway, it just doesn't pass decodeResource() To load pictures , This can explain , Why, no matter where res In the table of contents , The size of the image is calculated based on the resolution of the original image . If you have time, you can check the source code and verify it .

Look again. Glide The experiment of :


You can see ,Glide And fresco There's a big difference :

If you only get bitmap object , Then the memory occupied by the image is calculated according to the resolution of the original image . But if it passes into(imageView) Load a picture onto a control , Then the resolution will be compressed according to the size of the control .

Like the first one , The width and height of the displayed controls are 500dp = 750px, The resolution of the original image 1080*452, The final converted resolution is :750 * 314, So the picture memory size :750 * 314 * 4B = 94200B;

Like the last one , The width and height of the displayed control is 1920*984, The resolution of the original image is converted to :1920 * 984, So the picture memory size :1920 * 984 * 4B = 7557120B;

As for the rules of this transformation , I don't know , You can have a look at the source code when you have time , But that means ,Glide It will automatically convert the resolution according to the size of the displayed control , Then it is loaded into memory .

But whether it's Glide,fresco, Regardless of whether the source of the picture is res Inside , Regardless of the equipment dpi How much is the , Need and source res A resolution conversion of the directory .

therefore , In the chapter of image memory size , Will say , If you use an open source library image , that , Then the theory doesn't apply , Because the system is open inSampleSize Interface setup , It allows us to compress a certain proportion of the pictures that need to be loaded into memory , To reduce memory usage .

And these pictures are open source libraries , It is natural for the internal system to take advantage of these supports , Do some memory optimization , It may also involve other optimization processing such as image clipping , But anyway , here , The system's native theoretical basis for calculating the size of image memory is naturally not applicable .

Reduce the resolution , In addition to the default optimization processing inside the image open source library , Naturally, they will also provide relevant interfaces for us to use , such as :

//frescoImageRequestBuilder.newBuilderWithSource(uri)    .setResizeOptions(new ResizeOptions(500, 500)).build()

about fresco Come on , In this way , Manually reduce the resolution , In this way, the memory occupied by the picture will be reduced , But the specific interface is internal to the incoming (500, 500) How to deal with , I don't know yet , Because we know , The system is open API It only supports compression with a certain proportion of resolution , that fresco There must be a layer of processing and conversion inside .

One thing to note , I use fresco yes 0.14.1 edition , I don't know the higher version , This version of the setResizeOptions() The interface only supports jpg The format of the picture is valid , If necessary png Image processing , A lot of online , Self access .

Glide Words , Itself has been processed once according to the size of the control , If you have to deal with it manually , You can use it override() Method .

summary

Last , Let's summarize a little :

  • The calculation formula of the memory occupied by a picture : The resolution of the * Pixel size ; But the resolution is not necessarily the resolution of the original image , We need to combine some scenarios to discuss , There are several cases of pixel size :ARGB_8888(4B)、RGB_565(2B) wait .
  • If you don't optimize the picture , Such as compression 、 Cutting and other operations , that Android The system will decide whether to convert the resolution of the original image and then load it into memory according to different sources of the image .
  • The source of the picture is res When different resource directories within , The system will be based on the current status of the equipment dpi Value and the corresponding resource directory dpi value , Do a resolution conversion , The following rules : New resolution = The horizontal resolution of the original image * ( The equipment dpi / The directory corresponds to dpi ) * The vertical resolution of the original image * ( The equipment dpi / The directory corresponds to dpi ).
  • Source of other pictures , Disk , file , Flow, etc. , The memory size of the image is calculated according to the resolution of the original image .
  • jpg、png Just a container for pictures , The size of the image file itself has nothing to do with the memory it occupies .
  • Based on the above theory , The following scenarios are reasonable :
  • Same app, In different dpi In the device , The memory size of the same image on the same interface may be different .
  • Same app, The same picture , But the picture is placed in a different place res When in the resource directory in , The memory size may be different .
  • The above scenario may , Because , Once you use a popular image open source library , that , The above theory is basically not applicable .
  • Because the system supports the optimization of pictures , Allow pictures to be compressed first , Reduce the resolution before loading into memory , To achieve the purpose of reducing the occupied memory size
  • And the popular open source image library , There are basically some image optimization operations inside :
  • When using fresco when , No matter where the picture comes from , Even if it's res, The memory size occupied by the image is still calculated according to the resolution of the original image .
  • When using Glide when , If there is a control to set the picture display , Then it will be automatically according to the size of the control , Reduce the resolution of the picture . The source of the picture is res The resolution conversion rule of is also invalid for it .

The theories sorted out in this article 、 Basically by summarizing the content of other people's blogs , And do relevant experiments to verify , Come to a conclusion , The correctness is weaker than that of reading the source code itself , therefore , If there is something wrong , Welcome to point out . Have the time , You can also look at the relevant source code , Let's make sure .

原网站

版权声明
本文为[A bird carved in the desert]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/186/202207050941162544.html