java代码内存消耗过高排查思路

java代码内存消耗过高排查思路
有一台应用服务器的内存消耗加大,warnings;上去登录看看,top查看一下内存消耗最大的是java代码;和我的数据库没有啥关系,好奇心促使我
继续探究下去看看咋回事
top结果图如下

通过ps命令可以查到具体进程的CPU占用情况,但是不能查到一个进程下具体线程的内存占用情况ps -mp 2954 -o THREAD,tid,time,rss,size,%mem

那么通过jmap命令去核实一下(注意:此工具使用时,官方文档查询使用注意事项)
jmap -histo:live 2954 > /tmp/static.log 分析日志发现是char ,bytes占用大量的内存

jmap -dump:live,format=b file=/tmp/dump.log 2954利用mat工具分析内存情况,至此,我把相关信息收集完毕交由开发人员去处理问题

C指针1

C指针
C指针是C关键核心
一个变量的地址称为该变量的“指针”。例如地址2001是变量j的指针。
如果有一个变量专门用来存放另一变量的地址(即指针),则它称为“指针变量”。指针变量就是地址变量,用来存放地址,指针变量的值是地址。
指针是一个地址,指针变量是存放地址的变量
定义指针变量
 类型名 * 指针变量名 如:int *p_1,*p_2;
 
 #include<stdio.h>
int main(void)
{
 int i = 5,j = 1;
 int *p_1,*p_2;//定义指针变量
 p_1 = &i;//把变量的地址赋给指针变量
 p_2 = &j;
 printf("a=%d,b=%d\n",i,j);//输出变量值
 printf("&a=%d,&b=%d\n",&i,&j);//输出变量地址
 printf("*p_a=%d,*p_b=%d\n",*p_1,*p_2);//输出指针变量指向的值
 printf("p_a=%d,p_b=%d\n",p_1,p_2);//输出指针变量里存放的地址
 return 0;
}

从程序中得到如下信息:
1、指针变量前面的“*”表示该变量的类型为指针型变量。指针变量名是p_1和p_2,而不是*p_1,*p_2。所以赋值时赋给p_1,p_2.
2、在定义指针变量时必须指定基类型。指针的移动和运算涉及字节的长短问题,故需要基类型
3、一个变量的指针的含义包括两个方面,一是以存储单元编号表示的地址(如编号为2000的字节),一是它指向的存储单元的数据类型(如int\char\float等).
4、指针变量中只能存放地址(指针),不要将一个整数赋给一个指针变量

C引用指针变量的三种情况
1、给指针变量赋值
p=&a ===>将a的地址赋给指针变量p,指针变量p的值是变量a的地址,p指向a
2、引用指针变量指向的变量
*p=1;==>表示将整数1赋给p当前所指向的变量,如果p指向变量a,则相当于把1赋给a,即a=1
3、引用指针变量的值
printf(“%d”,p);==>作用是以10进制数形式输出指针变量p的值,如果p指向了a,就是输出了a的地址,即&a.

& 取地址运算符。&a是变量a的地址
* 指针运算符(或“间接访问”运算符),*p代表指针变量p指向的对象。

#include <stdio.h>
int main(void)
{
 int a,b;
 int *p1,*p2,*p;
 printf("Please enter the a,b valuse is :\n");
 scanf("%d,%d",&a,&b);
 p1 = &a;
 p2 = &b;
 printf("The old address p1=%d,p2=%d\n",p1,p2);
 if ( a<b )
 {
 p = p1; //交换了地址
 p1 = p2;
 p2 = p;
 }
 printf("The new address p1=%d,p2=%d\n",p1,p2);
 printf("a=%d,b=%d\n",a,b);
 printf("max=%d,min=%d\n",*p1,*p2);
 return 0;
}
/*
Please enter the a,b valuse is :
1,2
The old address p1=2686736,p2=2686732
The New address p1=2686732,p2=2686736
a=1,b=2
max=2,min=1
*/

指针变量作为函数参数
将一个变量的地址传送到另一个函数中

/*利用指针地址的传递来交换变量*/
#include<stdio.h>
int main(void)
{
 void max(int *,int *);//这里定义不能省略*符号,表示传递的变量是指针类型,如果不写,则在子函数行会报错
 int a,b;
 int *p_1,*p_2;
 printf("Please enter the a and b values:\n");
 scanf("%d,%d",&a,&b);//输入a,b值
 p_1 = &a;//将a,b地址赋值给整型指针变量p_1和p_2
 p_2 = &b;
 if(a<b)
 max(p_1,p_2);//传递指针变量内放两个变量的地址
 printf("The DESC values is :%d,%d",*p_1,*p_2);
 return 0;
}
void max(int *p1,int *p2)
{
 int t;
 t = *p1;//交换指针变量里的值
 *p1 = *p2;
 *p2 = t;
}

数组元素的指针
一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的
地址放到一个指针变量中)。所谓数组元素的指针就是数组元素的地址。
int *p=&a[0];<====>int *p;p=&a[0];<===>int *p=a;
至此,引用一个数组元素,有下面两种方式
下标法==>a[i];
指针法==>*(a+i)或*(p+i).其中a是数组名,p是指向数组元素的指针变量

/*如果在利用指针对数组里元素进行访问时,要注意指针的指向及
移动情况,如果越界的话,一般不会出错,但是逻辑上是有问题的,不能获得你想要的结果
*/
#include<stdio.h>
int main(void)
{
 int a[10],*p=a;
 int i,j;
 printf("please enter the ten number values is :\n");
 for ( i=0;i<10;i++ )
 {
 scanf("%d",p++);
 }
 p = a;//这里的处理是将指针重新指向a[0],因通过上步的循环处理,指针已经指向了a[9]这个地址,如果再做循环则是错误的数据
 for ( j=0;j<10;j++,p++)
 {
 printf("%d\t",*p);
 }
 return 0;
}

指针几个场景的小技巧
1、
p++;
*p;
p++使p指向下一元素a[1]。然后若再执行*p,则得到下一个元素a[1]的值。
2、
*p++
由于++和*同优先级,结合方向为自右而左,因此它等价于*(p++)。先引用p的值,实现*p的运算,然后再使p自增1.
3、
*(p++)与*(++p)作用
前者是先取*p值,然后使p加1.后者是先使p加1,再取*p。
若p初值为a(即&a[0]),若输出*(p++),得到a[0]的值,而输出*(++p),得到a[1]的值。
4、++(*p)
表示p所指向的元素值加1,如果p=a,则++(*p)相当于++a[0],若a[0]的值为3,则执行++(*p)(即++a[0])后a[0]的值为4。
注意:是元素a[0]的值加1,而不是指针p的值加1.
5、
如果p当前指向a数组中第i个元素a[i],则:
*(p–)相当于a[i–],先对p进行”*”运算(求p所指向的元素的值),再使p自减
*(++p)相当于a[++i],先使p自加,再进行”*”运算
*(–p)相当于a[–i],先使p自减,再进行”*”运算

C变量

C语言变量
一、范围考虑
C语言中变量的作用域是个比较重要的知识点。
分为局部变量和全局变量
局部变量:函数内定义,只在此函数内有效,函数调用完,会在内存中释放;在复合语句中,只在复合语句中有效,出此复合语句后无效;main函数内的变量也不例外;形参也是局部变量
全局变量:在函数外定义的变量为全局变量。
一般情况下,C语言中的全局变量首字母为大写,但并非必须要大写,只是一个好的习惯而已

/*测试全局变量使用*/
#include<stdio.h>
float Max=0,Min=0;//定义全局变量
int main(void)
{
 int i;
 float average( float score[10],int );
 float score[10];
 printf("Please enter the ten student's score is :\n");
 for ( i=0;i<10;i++ )
 {
 scanf("%f",&score[i]);
 }
 printf("Max=%5.2f\nMin=%5.2f\naverage=%5.2f\n",Max,Min,average(score,10));
 return 0;
}
float average( float arry[],int num )
{
 int j,i,k;
 float m,sum=0;
 for ( i=0;i<=num-1;i++ )
 {
 for ( j=1;j<=num-i-1;j++ )
 {
 if ( arry[j-1]>arry[j] )
 {
 m = arry[j];
 arry[j] = arry[j-1];
 arry[j-1]= m;
 }
 }
 sum += arry[i];
 }
 for ( k=0;k<=num-1;k++ )
 {
 if ( k==9 )
 Max = arry[k];
 if ( k==0 )
 Min = arry[k];
 }
 return(sum/num);
}

二、生命周期考虑
有的变量在程序的运行的整个过程都是存在的,而有的变量则是在调用其所在的函数时才临时分配存储单元,而在函数调用结束后该存储单元就马上释放了,
变量不存在了。即变量以静态存储方式和动态存储方式。
静态存储方式是指在程序运行期间由系统分配固定的存储空间的方式,
动态存储则是在程序运行期间根据需要进行动态的分配存储空间的方式。

在C语言中,每一个变量和函数都有两个属性:数据类型和数据的存储类别。
C语言的存储类别包括4种:自动的(auto)、静态的(statis)、寄存器的(register)、外部的(extern)
可以根据变量存储类别来得知其生命周期或者作用范围

==>局部变量的存储类型<==
auto类别:
如果在定义参数的时候不专门声明static存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。函数形参,函数中变量,复合语句中的变量等都是
auto关键字可省略,隐含指定为auto
static类别:
a、有时希望函数中的局部变量的值在函数调用结束后不消失而继续保留原值,即其占用的存储单元不释放,在下一次再调用该函数时,该变量已有值(即上一次函数调用结束时值)。
b、对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而是保留上次函数结束时的值。而对自动变量赋初值,
不是编译时进行的,而是在函数调用时进行的,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
c、static变量不赋初值,编译时会自动给0或者’\0’;auto变量则其值不确定
d、不能本函数以外的函数调用,包括main函数
利用static关键字进行声明

#include<stdio.h>
int main(void)
{
 int f(int);
 int a=2,i;
 for ( i=0;i<3;i++ )
 {
 printf("%d\n",f(a));
 }
 return 0;
}
int f(int a)
{
 auto int b=0;
 static int c=3;//声明静态变量
 b=b+1;
 c=c+1;
 return(a+b+c);
}

register类别:
频繁使用的变量可以直接放到cpu中的寄存器中,从而提高的执行的效率。在现在的计算机中,优化的编译系统会将一些使用频繁的变量自动放到寄存器中,而
无需程序设计者指定。

3种局部变量的存储位置是不同的:auto存储在动态存储区;static存储在静态存储区;寄存器存储在cpu中的寄存器中。

==>全局变量的存储类型<==
全局变量是存放在静态存储区中的。因此它们的生存期是固定的,存在于程序的整个运行过程。那么他们的作用域是什么范围?
外部变量是在函数的外部定义的全局变量,它的作用域是从变量的定义处开始,到本程序的末尾。
故可用extern来扩展外部变量声明

/×在一个文件内扩展外部变量的作用域×/
#include<stdio.h>
int main(void)
{ extern int A,B,C;//把外部函数A\B\C的作用域扩展到从此处开始
 int max();
 printf("Please enter three integer numbers:\n");
 scanf("%d%d%d",&A,&B,&C);
 printf("The Max result is :%d\n",max());
 return 0;
}
int A,B,C;//建议将函数定义到所引用的函数之前,这样就无需用到extern,来扩展作用域了
int max()
{
 int m;
 m = A>B?A:B;
 return(m>C?m:C);
}
/*文件外的变量作用域
在44.c的文件里定义了一个全局变量A,
在45.c的文件里利用extern来扩展44.c定义的变量,从而在
文件范围内扩展变量范围
*/
/×44.c文件×/
#include<stdio.h>
#include "45.c"//链接45.c文件
int A;
int main(void)
{
 int b =10;
 int c,m,d;
 printf("Please enter the values is :\n");
 scanf("%d,%d",&A,&m);
 c = A*b;
 printf("%d*%d = %d\n",A,b,c);
 d = pw(m);
 printf("%d^%d = %d\n",A,m,d);
 return 0;
}
/×45.c文件×/
#include<stdio.h>
extern A;
int pw (int n)
{
 int i,s=1;
 for ( i=1;i<=n;i++)
 s *= A;
 return(s);
}

注意:在编译遇到extern时,现在本文件中找外部变量的定义,如果找到,就在本文件中扩展作用域;
如果找不到,就在链接时从其他文件中找外部变量的定义,找到则扩展到本文件中,找不到则报错。

通过加static来限制外部的变量只能在本文件中使用如:
#include<sdtio.h>
static int a;//这里的a只能在此文件中扩展,其它文件获取不到,这种也称为静态外部变量
int main(){}
void funcation(){}
….

C函数

C函数
1、一个C程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。对较大的程序,一般不希望把所有内容全放在一个文件中,而是将它们分别放在若干个
源文件中,由若干个源程序文件组成一个C程序。这样便于分别编写和编译,提高调试效率。一个源程序文件可以为多个C程共用。
2、一个源程序文件由一个或多个函数以及其他有关内容(如指令、数据声明与定义等)组成。一个源程序文件时一个编译单位,在程序编译时是以源程序文件为单位进行编译的,
而不是以函数为单位进行编译的。
3、C程序的执行时从main函数开始的,如果在main函数中调用其他函数,在调用后流程返回到main函数,在main函数中结束整个程序的运行。main函数不可被其他函数调用,只可被
操作系统调用。函数不能嵌套,函数是相互独立平行的。
4、函数分有参数函数和无参数函数,也分库函数和自定义函数

函数定义
1、指定函数的名字,便于调用
2、指定函数类型,即函数返回值的类型
3、指定函数的参数的名字和类型,以便在调用函数时向它们传递数据。对无参数函数不需要这项
4、指定函数应当完成什么操作,即函数功能
类型名 函数名()
{
函数体
}

函数调用时的数据传递
1、形式参数和实际参数
2、实参和形参间的数据传递,即形参从实参里得到一个值,该值在函数调用期间有效,可以参加该函数中的运算。

#include<stdio.h>
int main(void)
{
 float a,b;
 int max(float,float);//另一种形式int max(float a,float b);
 printf("please enter the a,b values:\n");
 scanf("%d,%d",&a,&b);
 printf("the Max values is %d\n",max(a,b));//实参
 return 0;
}
int max (float x,float y)//形参
{
 int z;
 z = x>y?x:y;
 return z;//如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准。对数值类型数据,可以自动进行类型转换。
}
//简单逻辑函数多层嵌套调用,main调max1,max1调max2,max2调max3,然后依次返回
#include<stdio.h>
int x,y,z;
int main(void)
{
 int max1(int,int,int,int);
 int a,b,c,d;
 int max;
 printf("please enter a,b,c,d \n");
 scanf("%d,%d,%d,%d",&a,&b,&c,&d);
 max = max1(a,b,c,d);
 printf("%d",max);
 return 0;
}
int max1 (int a, int b,int c,int d)
{
 int max2(int,int,int);
 x = a>b?a:b ;
 return (max2(x,c,d));
}
int max2 ( int x,int c,int d)
{
 int max3(int,int);
 y = x>c?x:c;
 return( max3(y,d));
}
int max3(int y,int d)
{
 return(y>d?y:d);
}
//简单递归调用
#include<stdio.h>
int main(void)
{
 int f_age(int);
 printf("the age is %d\n",f_age(5));
 return 0;
}
int f_age(int num)
{
 int age;
 if ( num==1 )
 {
 age = 10;
 return(age);
 }
 else
 {
 return(f_age(num-1)+2);
 }
}
调用有参数函数时,需要提供实参。实参可以是常量、变量或表达式。数组元素的作用与变量相当,一般来说,凡是变量可以出现的地方,都可以用数组元素代替。
数组元素可以用作函数参数。数组名也可以作实参和形参,用数组名作函数实参时,向形参(数组名或指针变量)传递的是数组首元素的地址。
数组元素可以用作函数实参,不能用作形参。因为形参是在函数调用时临时分配存储单元的,不可能为一个数组元素单独分配存储单元
//求输入10个数字的最大数及位置,因为求其位置,需用数组来记录其输入的位置;
#include<stdio.h>
int main(void)
{
 int a[10];
 int i,j,m,n;
 int max2(int,int);
 printf("please enter the ten int valus:\n");
 for ( i=0;i<=9;i++ )
 {
 scanf("%d",&a[i]);
 }
 printf("\n");
 for ( j=1,m=a[0];j<=9;j++ )
 {
 if ( max2(m,a[j])> m )//传递数组元素的值来调用有参数函数
 {
 m = max2(m,a[j]);
 n = j;
 }
 }
 printf("the max values %d,the max values position:%d\n",m,n+1);
 return 0;
}
int max2(int x,int y)
{
 return (x>y?x:y);
}
#include<stdio.h>
int main(void)
{
 float score[10],aver;
 float average(float score[10]);
 int i;
 printf("Please enter the 10's score values:\n");
 for ( i=0;i<9;i++ )
 scanf("%f",&score[i]);
 printf("\n");
 printf("The student's average values is :%5.2f\n",average(score));//利用数组名去调用
 return 0;
}
float average(float score1[10])
{
 int j;
 float sum = score1[0];
 for ( j=1;j<=9;j++)
 sum += score1[j];
 return (sum/10);
}
/*数组方式针对正整数进行升序*/
#include <stdio.h>
int main(void)
{
 void sort(int a[],int n);
 int a[10];
 int i,j;
 printf("Please the int ten's values :\n");
 for ( i=0;i<10;i++ )
 {
 scanf("%d",&a[i]);
 }
 sort(a,10);
 printf("the result of sort is :\n");
 for ( j=0;j<=9;j++ )
 {
 printf("%d\n",a[j]);
 }
 return 0;
}
void sort (int arry[],int num)
{
 int k,j,i,h;
 for ( i=0;i<num-1;i++)
 {
 k = i;
 for ( j=i+1;j<num;j++ )
 {
 if (arry[i]>arry[j])
 {
 h = arry[i];
 arry[i] = arry[j];
 arry[j] = h;
 }
 }
 }
}
/*判断二维数组中最大的元素的值*/
#include <stdio.h>
int main(void)
{
 int max(int a[3][4],int,int);
 int a[3][4]={{123,920,-123,3543},{1,787123123,-343,9},{132431,0,102,108}};
 printf("%d\n",max(a,3,4));
 return 0;
}
int max(int a[][4],int x,int y)
{
 int i,j,m;
 m = a[0][0];
 for ( i=0;i<x;i++ )
 {
 for ( j=0;j<y;j++ )
 {
 m<a[i][j]?(m=a[i][j]):m;
 }
 }
 return(m);
}